> ## Documentation Index
> Fetch the complete documentation index at: https://docs.permutive.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Page Tracking

> Track pages and screens with automatic engagement metrics

**PageTracker is the recommended approach** for tracking user interactions in the Permutive Android SDK. It provides automatic Pageview event tracking, engagement metrics, and seamless integration with Permutive's insights platform.

<CardGroup cols={4}>
  <Card title="Basic Usage" href="#basic-usage" icon="code" />

  <Card title="Lifecycle" href="#lifecycle-management" icon="arrows-rotate" />

  <Card title="Engagement" href="#tracking-engagement" icon="chart-line" />

  <Card title="Use Cases" href="#use-cases" icon="layer-group" />
</CardGroup>

## Why Use PageTracker?

PageTracker is the primary tracking method because it:

* **Integrates with standard events** - Works seamlessly with Permutive's event schema
* **Tracks engagement automatically** - Measures time spent and scroll depth
* **Enables contextual cohorts** - Supports content-based targeting when URLs are provided
* **Provides better insights** - Delivers richer data to the Permutive platform
* **Associates related events** - Groups events with page context

<Tip>
  Default to PageTracker for tracking screens and content views in your app. Use EventTracker only for standalone events not associated with a page or screen.
</Tip>

***

## Basic Usage

### Creating a PageTracker

A PageTracker object should be created when the user starts viewing a page/screen, and closed when viewing finishes.

<CodeGroup>
  ```kotlin Kotlin theme={"dark"}
  import androidx.appcompat.app.AppCompatActivity
  import android.net.Uri
  import android.os.Bundle
  import com.permutive.android.EventProperties
  import com.permutive.android.PageTracker

  class ArticleActivity : AppCompatActivity() {

      private val permutive by lazy {
          (application as MyApplication).permutive
      }

      private lateinit var pageTracker: PageTracker

      override fun onCreate(savedInstanceState: Bundle?) {
          super.onCreate(savedInstanceState)
          setContentView(R.layout.activity_article)

          // Create the PageTracker with properties
          pageTracker = permutive.trackPage(
              title = "Article Title",
              url = Uri.parse("https://www.example.com/article"),
              referrer = Uri.parse("https://www.example.com/home"),
              eventProperties = EventProperties.from(
                  "article_id" to 12345,
                  "category" to "technology",
                  "author" to "John Doe"
              )
          )
      }

      override fun onPause() {
          super.onPause()
          pageTracker.pause()
      }

      override fun onResume() {
          super.onResume()
          pageTracker.resume()
      }

      override fun onDestroy() {
          super.onDestroy()
          pageTracker.close()
      }
  }
  ```

  ```java Java theme={"dark"}
  import androidx.appcompat.app.AppCompatActivity;
  import android.net.Uri;
  import android.os.Bundle;
  import com.permutive.android.EventProperties;
  import com.permutive.android.PageTracker;

  public class ArticleActivity extends AppCompatActivity {

      private PageTracker pageTracker;

      @Override
      protected void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
          setContentView(R.layout.activity_article);

          Permutive permutive = ((MyApplication) getApplication()).getPermutive();

          // Create the PageTracker with properties
          EventProperties properties = new EventProperties.Builder()
              .with("article_id", 12345)
              .with("category", "technology")
              .with("author", "John Doe")
              .build();

          pageTracker = permutive.trackPage(
              properties,
              "Article Title",
              Uri.parse("https://www.example.com/article"),
              Uri.parse("https://www.example.com/home")
          );
      }

      @Override
      protected void onPause() {
          super.onPause();
          pageTracker.pause();
      }

      @Override
      protected void onResume() {
          super.onResume();
          pageTracker.resume();
      }

      @Override
      protected void onDestroy() {
          super.onDestroy();
          pageTracker.close();
      }
  }
  ```
</CodeGroup>

***

## Lifecycle Management

### When to Create

Create the PageTracker in `onCreate()`:

```kotlin theme={"dark"}
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    
    pageTracker = permutive.trackPage(...)  // Create early
    loadContent()  // Then load your content
}
```

### When to Pause/Resume

Call `pause()` and `resume()` to track engagement time accurately:

```kotlin theme={"dark"}
override fun onPause() {
    super.onPause()
    // User can't see the page - stop tracking time
    pageTracker.pause()
}

override fun onResume() {
    super.onResume()
    // User can see the page again - resume tracking time
    pageTracker.resume()
}
```

### When to Close

Always close the PageTracker when done:

```kotlin theme={"dark"}
override fun onDestroy() {
    super.onDestroy()
    // Page viewing finished - send completion event
    pageTracker.close()
}
```

> ⚠️ Important: Always Close
>
> Failing to close PageTracker can lead to memory leaks and inaccurate engagement metrics.

***

## Tracking Engagement

### Tracking Time Spent

PageTracker automatically tracks time spent by using `pause()` and `resume()`:

```kotlin theme={"dark"}
class ArticleActivity : AppCompatActivity() {
    
    private lateinit var pageTracker: PageTracker
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        pageTracker = permutive.trackPage(...)
        // Time tracking starts automatically
    }
    
    override fun onPause() {
        super.onPause()
        pageTracker.pause()  // Pause time tracking
    }
    
    override fun onResume() {
        super.onResume()
        pageTracker.resume()  // Resume time tracking
    }
    
    override fun onDestroy() {
        super.onDestroy()
        pageTracker.close()  // Final engaged time sent
    }
}
```

The engaged time is sent in the PageviewComplete event when you call `close()`.

### Tracking Scroll Depth

Use `updatePercentageViewed()` to track how much content the user has read:

<CodeGroup>
  ```kotlin Kotlin theme={"dark"}
  class ArticleActivity : AppCompatActivity() {

      private lateinit var pageTracker: PageTracker

      override fun onCreate(savedInstanceState: Bundle?) {
          super.onCreate(savedInstanceState)
          setContentView(R.layout.activity_article)

          pageTracker = permutive.trackPage(...)

          // Add scroll listener
          scrollView.viewTreeObserver.addOnScrollChangedListener {
              val contentHeight = scrollView.getChildAt(0).height
              val visibleHeight = scrollView.scrollY.toFloat() + scrollView.height
              val percentageViewed = visibleHeight / contentHeight

              pageTracker.updatePercentageViewed(percentageViewed)
          }
      }
  }
  ```

  ```java Java theme={"dark"}
  public class ArticleActivity extends AppCompatActivity {

      private PageTracker pageTracker;

      @Override
      protected void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
          setContentView(R.layout.activity_article);

          pageTracker = permutive.trackPage(...);

          ScrollView scrollView = findViewById(R.id.scrollView);

          // Add scroll listener
          scrollView.getViewTreeObserver().addOnScrollChangedListener(
              new ViewTreeObserver.OnScrollChangedListener() {
                  @Override
                  public void onScrollChanged() {
                      float contentHeight = scrollView.getChildAt(0).getHeight();
                      float visibleHeight = scrollView.getScrollY() + scrollView.getHeight();
                      float percentageViewed = visibleHeight / contentHeight;

                      pageTracker.updatePercentageViewed(percentageViewed);
                  }
              }
          );
      }
  }
  ```
</CodeGroup>

**RecyclerView Example:**

```kotlin theme={"dark"}
recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
    override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
        val layoutManager = recyclerView.layoutManager as LinearLayoutManager
        val totalItems = layoutManager.itemCount
        val lastVisibleItem = layoutManager.findLastVisibleItemPosition()
        
        val percentageViewed = (lastVisibleItem + 1).toFloat() / totalItems
        pageTracker.updatePercentageViewed(percentageViewed)
    }
})
```

***

## Tracking Additional Events

Track other events associated with the page using PageTracker's `track()` methods:

<CodeGroup>
  ```kotlin Kotlin theme={"dark"}
  class ArticleActivity : AppCompatActivity() {

      private lateinit var pageTracker: PageTracker

      override fun onCreate(savedInstanceState: Bundle?) {
          super.onCreate(savedInstanceState)

          pageTracker = permutive.trackPage(...)

          // Track page-related events
          shareButton.setOnClickListener {
              pageTracker.track(
                  "ArticleShared",
                  EventProperties.from(
                      "share_method" to "twitter"
                  )
              )
          }

          commentButton.setOnClickListener {
              pageTracker.track("CommentAdded")
          }
      }
  }
  ```

  ```java Java theme={"dark"}
  public class ArticleActivity extends AppCompatActivity {

      private PageTracker pageTracker;

      @Override
      protected void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);

          pageTracker = permutive.trackPage(...);

          // Track page-related events
          shareButton.setOnClickListener(v -> {
              EventProperties props = new EventProperties.Builder()
                  .with("share_method", "twitter")
                  .build();
              pageTracker.track("ArticleShared", props);
          });

          commentButton.setOnClickListener(v -> {
              pageTracker.track("CommentAdded");
          });
      }
  }
  ```
</CodeGroup>

***

## URL Schemes

### Web Content

For web content, use full URLs:

```kotlin theme={"dark"}
pageTracker = permutive.trackPage(
    title = "Article Title",
    url = Uri.parse("https://www.example.com/articles/tech-news"),
    referrer = Uri.parse("https://www.example.com/home")
)
```

### App Screens

For native app screens, use custom URI schemes:

```kotlin theme={"dark"}
// Option 1: app:// scheme
pageTracker = permutive.trackPage(
    title = "Home Screen",
    url = Uri.parse("app://home")
)

// Option 2: your-app:// scheme
pageTracker = permutive.trackPage(
    title = "Profile Screen",
    url = Uri.parse("myapp://profile/user/12345")
)

// Option 3: https with app path
pageTracker = permutive.trackPage(
    title = "Settings",
    url = Uri.parse("https://app.example.com/settings")
)
```

> 💡 URLs Enable Contextual Cohorts
>
> When you provide URLs, Permutive can generate contextual cohorts based on content analysis. This works for publicly accessible web URLs.

***

## Events Generated

PageTracker automatically generates these events:

### Pageview Event

Tracked when PageTracker is created:

```
Event: Pageview
Properties:
  - title: "Article Title"
  - url: "https://www.example.com/article"
  - referrer: "https://www.example.com/home"
  - [your custom properties]
```

### PageviewComplete Event

Tracked when PageTracker is closed:

```
Event: PageviewComplete
Properties:
  - engaged_time: 45.2 (seconds)
  - completion: 0.75 (75% viewed)
  - [your custom properties]
```

### PageviewEngagement Events

Periodic engagement events (if configured):

```
Event: PageviewEngagement
Properties:
  - engaged_time: 15.0 (seconds)
  - [your custom properties]
```

***

## Use Cases

<AccordionGroup>
  <Accordion title="News/Content App" icon="newspaper">
    ```kotlin theme={"dark"}
    class ArticleActivity : AppCompatActivity() {

        private lateinit var pageTracker: PageTracker

        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)

            val article = intent.getParcelableExtra<Article>("article")

            pageTracker = permutive.trackPage(
                title = article.title,
                url = Uri.parse(article.url),
                referrer = Uri.parse(intent.getStringExtra("referrer")),
                eventProperties = EventProperties.from(
                    "article_id" to article.id,
                    "category" to article.category,
                    "author" to article.author,
                    "published_at" to article.publishedDate,
                    "word_count" to article.wordCount
                )
            )

            setupScrollTracking()
        }
    }
    ```
  </Accordion>

  <Accordion title="E-Commerce Product Page" icon="cart-shopping">
    ```kotlin theme={"dark"}
    class ProductActivity : AppCompatActivity() {

        private lateinit var pageTracker: PageTracker

        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)

            val product = viewModel.product.value

            pageTracker = permutive.trackPage(
                title = product.name,
                url = Uri.parse("app://product/${product.id}"),
                eventProperties = EventProperties.from(
                    "product_id" to product.id,
                    "product_name" to product.name,
                    "category" to product.category,
                    "price" to product.price,
                    "in_stock" to product.inStock
                )
            )

            addToCartButton.setOnClickListener {
                pageTracker.track(
                    "ProductAddedToCart",
                    EventProperties.from(
                        "product_id" to product.id,
                        "quantity" to 1
                    )
                )
            }
        }
    }
    ```
  </Accordion>

  <Accordion title="Video App (Non-Video Content)" icon="video">
    For video content itself, use [MediaTracker](/sdks/mobile/android/features/video-tracking). For video details/description pages:

    ```kotlin theme={"dark"}
    class VideoDetailsActivity : AppCompatActivity() {

        private lateinit var pageTracker: PageTracker

        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)

            pageTracker = permutive.trackPage(
                title = video.title,
                url = Uri.parse("app://video/${video.id}/details"),
                eventProperties = EventProperties.from(
                    "video_id" to video.id,
                    "video_title" to video.title,
                    "genre" to video.genre,
                    "duration_seconds" to video.durationSeconds
                )
            )

            playButton.setOnClickListener {
                pageTracker.track("VideoPlayButtonClicked")
                startVideoPlayer()
            }
        }
    }
    ```
  </Accordion>
</AccordionGroup>

***

## When to Use PageTracker vs EventTracker

### Use PageTracker When:

* ✅ Tracking article/content views
* ✅ Tracking screen views in your app
* ✅ Measuring time spent on a page/screen
* ✅ Tracking scroll depth
* ✅ You want contextual cohorts
* ✅ Events are associated with a page context

### Use EventTracker Only When:

* ⚠️ Tracking standalone events (button clicks not tied to pages)
* ⚠️ Tracking background events
* ⚠️ Events have no page context

> 💡 Default to PageTracker
>
> Most customer implementations should primarily use PageTracker. EventTracker is for specific use cases.

See [Event Tracking](/sdks/mobile/android/features/event-tracking) for EventTracker documentation.

***

## Troubleshooting

<AccordionGroup>
  <Accordion title="PageTracker Not Tracking Time">
    **Problem:** Engaged time is always 0.

    **Cause:** Not calling `pause()` and `resume()`.

    **Solution:** Implement lifecycle callbacks:

    ```kotlin theme={"dark"}
    override fun onPause() {
        super.onPause()
        pageTracker.pause()  // IMPORTANT
    }

    override fun onResume() {
        super.onResume()
        pageTracker.resume()  // IMPORTANT
    }
    ```
  </Accordion>

  <Accordion title="Memory Leaks">
    **Problem:** App memory usage grows over time.

    **Cause:** Not closing PageTracker.

    **Solution:** Always close in `onDestroy()`:

    ```kotlin theme={"dark"}
    override fun onDestroy() {
        super.onDestroy()
        pageTracker.close()  // IMPORTANT
    }
    ```
  </Accordion>

  <Accordion title="Contextual Cohorts Not Working">
    **Problem:** No contextual cohorts for pages.

    **Causes:**

    1. Feature not enabled
    2. Not providing URLs
    3. URLs not publicly accessible

    **Solutions:**

    1. Contact Customer Success Manager to enable
    2. Always provide URLs in `trackPage()`
    3. Ensure URLs are publicly accessible for web content

    See [Contextual Data](/sdks/mobile/android/core-concepts/contextual-data) for details.
  </Accordion>

  <Accordion title="Events Not Appearing">
    **Problem:** Pageview events not tracked.

    **Solutions:**

    1. Enable debug logging: `permutive.setDeveloperMode(true)`
    2. Check logs for "Published events with names (Pageview)"
    3. Verify event properties match your schema
    4. See [Verification Guide](/sdks/mobile/android/getting-started/verification)
  </Accordion>
</AccordionGroup>

***

## Best Practices

<Tabs>
  <Tab title="Do">
    * Create PageTracker in `onCreate()`
    * Call `pause()` in `onPause()`
    * Call `resume()` in `onResume()`
    * Call `close()` in `onDestroy()`
    * Provide URLs when possible for contextual cohorts
    * Track scroll depth for content pages
    * Use PageTracker for all page/screen views
  </Tab>

  <Tab title="Don't">
    * Forget to close PageTracker
    * Create multiple PageTrackers for the same page
    * Skip pause/resume calls
    * Use EventTracker when PageTracker is more appropriate
  </Tab>
</Tabs>

***

## Related Documentation

<CardGroup cols={2}>
  <Card title="Quick Start Guide" icon="rocket" href="/sdks/mobile/android/getting-started/quick-start">
    Get started with the SDK
  </Card>

  <Card title="Event Properties" icon="list" href="/sdks/mobile/android/core-concepts/event-properties">
    Add structured data to events
  </Card>

  <Card title="Contextual Data" icon="bullseye" href="/sdks/mobile/android/core-concepts/contextual-data">
    Content-based segmentation
  </Card>

  <Card title="Event Tracking" icon="bolt" href="/sdks/mobile/android/features/event-tracking">
    For standalone events
  </Card>

  <Card title="Video Tracking" icon="video" href="/sdks/mobile/android/features/video-tracking">
    For video content
  </Card>

  <Card title="Verification Guide" icon="check" href="/sdks/mobile/android/getting-started/verification">
    Verify your integration
  </Card>
</CardGroup>

***

## API Reference

For complete API documentation, see the [Javadocs](https://sdk-docs.permutive.com/index.html).

### PageTracker Interface

* `pause()` - Pause engagement tracking
* `resume()` - Resume engagement tracking
* `updatePercentageViewed(percentage: Float)` - Update scroll depth
* `track(eventName: String)` - Track event with this page context
* `track(eventName: String, properties: EventProperties?)` - Track event with properties
* `close()` - Complete page tracking and send PageviewComplete event
