Skip to main content
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.

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
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.

Basic Usage

Creating a PageTracker

A PageTracker object should be created when the user starts viewing a page/screen, and closed when viewing finishes.
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()
    }
}

Lifecycle Management

When to Create

Create the PageTracker in onCreate():
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:
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:
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():
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:
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)
        }
    }
}
RecyclerView Example:
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:
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")
        }
    }
}

URL Schemes

Web Content

For web content, use full URLs:
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:
// 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

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()
    }
}
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
                )
            )
        }
    }
}
For video content itself, use MediaTracker. For video details/description pages:
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()
        }
    }
}

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 for EventTracker documentation.

Troubleshooting

Problem: Engaged time is always 0.Cause: Not calling pause() and resume().Solution: Implement lifecycle callbacks:
override fun onPause() {
    super.onPause()
    pageTracker.pause()  // IMPORTANT
}

override fun onResume() {
    super.onResume()
    pageTracker.resume()  // IMPORTANT
}
Problem: App memory usage grows over time.Cause: Not closing PageTracker.Solution: Always close in onDestroy():
override fun onDestroy() {
    super.onDestroy()
    pageTracker.close()  // IMPORTANT
}
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 for details.
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

Best Practices

  • 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


API Reference

For complete API documentation, see the Javadocs.

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