Skip to main content
Ad responses include tracking URLs that must be fired to record impressions and clicks. How you fire them depends on your integration type.

Tracking URLs

The click URL (url) contains the tracking URLs as query parameters:
https://ssp.thrads.ai/api/v1/tracking/redirect?token=...&view_url=...&thrad_view_url=...
Query paramPurpose
view_urlDSP impression tracker. Fire when the ad is viewable.
thrad_view_urlSSP impression tracker. Fire when the ad is viewable (same timing as view_url).
For browser integrations, the publisher tag extracts and fires these automatically from the click URL. For mobile, you need to extract them from the url query string and fire them yourself.

Web / Browser Integration

For browser-based integrations (websites, web apps), use the Thrads Publisher Tag — a lightweight script that automatically tracks viewability using IntersectionObserver.

Publisher Tag Setup

Follow the publisher tag quickstart for browser-based tracking
The tag handles:
  • Rendered — element exists in DOM
  • In view — element enters viewport
  • Viewable — 50% visible for at least 1 second (IAB standard)
  • View end — element leaves viewport or page closes
No manual tracking code needed — just wrap your ad in a container with the redirect URL as an <a href> and the tag does the rest.

Mobile Integration (iOS / Android)

Mobile apps don’t run the publisher tag. You need to extract and fire the tracking URLs yourself.

1. Extract Tracking URLs from the Click URL

Parse view_url and thrad_view_url from the url query string:
// iOS (Swift)
func extractTrackingUrls(from clickUrl: String) -> (viewUrl: String?, thradViewUrl: String?) {
    guard let components = URLComponents(string: clickUrl) else { return (nil, nil) }
    let viewUrl = components.queryItems?.first(where: { $0.name == "view_url" })?.value
    let thradViewUrl = components.queryItems?.first(where: { $0.name == "thrad_view_url" })?.value
    return (viewUrl, thradViewUrl)
}
// Android (Kotlin)
fun extractTrackingUrls(clickUrl: String): Pair<String?, String?> {
    val uri = Uri.parse(clickUrl)
    return Pair(uri.getQueryParameter("view_url"), uri.getQueryParameter("thrad_view_url"))
}

2. Fire Impressions on Viewability

When the ad becomes viewable (at least 50% visible for 1 second), fire both URLs:
// iOS (Swift)
func fireTrackingPixels(viewUrl: String?, thradViewUrl: String?) {
    [viewUrl, thradViewUrl].compactMap { $0 }.forEach { urlString in
        guard let url = URL(string: urlString) else { return }
        URLSession.shared.dataTask(with: url).resume()
    }
}
IAB Viewability Standard: Only fire the impression when the ad is at least 50% visible in the viewport for at least 1 second. Firing on render (before the user sees it) inflates impression counts and hurts your analytics accuracy.

3. Handle Clicks

When the user taps the ad, open the url field. It records the click and redirects to the advertiser’s landing page:
// iOS
if let clickUrl = URL(string: bid.url) {
    UIApplication.shared.open(clickUrl)
}
The redirect happens server-side — the user ends up on the advertiser’s site.

Testing in Staging

Staging API keys return test ads with real tracking URLs. You can use these to verify your tracking integration fires correctly:
  • view_url — will return 204 No Content (impression not recorded since there’s no pending payload, but confirms connectivity)
  • url (click) — will redirect to a test page
This lets you validate the full flow without affecting production analytics.