Skip to content
Tolinku
Tolinku
Sign In Start Free
Analytics & Attribution · · 5 min read

Postback URLs for Mobile Attribution: How They Work

By Tolinku Staff
|
Tolinku mobile attribution dashboard screenshot for analytics blog posts

A postback URL is a server-to-server callback that fires when a conversion event occurs. When a user installs your app, your attribution system sends an HTTP request to the ad network's postback URL with the install details: campaign ID, device identifier, timestamp, and any custom data. The ad network uses this data to optimize its campaigns and report conversions.

This guide covers how postback URLs work in mobile attribution. For the install attribution flow, see install attribution flow: from ad click to first open. For webhook integrations, see webhooks and integrations for deep linking.

How Postback URLs Work

The Flow

1. User clicks ad on Ad Network A
2. Ad Network A records click with click_id=ABC123
3. User installs and opens app
4. Attribution provider determines Ad Network A drove the install
5. Attribution provider sends HTTP GET/POST to Ad Network A's postback URL:
   https://postback.adnetwork-a.com/install?click_id=ABC123&app_id=com.yourapp&event=install
6. Ad Network A records the conversion and optimizes future ad delivery

Postback URL Structure

A typical postback URL uses macro placeholders that the attribution provider replaces with actual values:

https://postback.adnetwork.com/conversion?
  click_id={click_id}&
  app_id={app_id}&
  event_name={event_name}&
  event_time={event_time}&
  device_id={device_id}&
  revenue={revenue}&
  currency={currency}

The macros (values in curly braces) are replaced at send time:

https://postback.adnetwork.com/conversion?
  click_id=ABC123&
  app_id=com.yourapp&
  event_name=install&
  event_time=1720780200&
  device_id=hashed_gaid&
  revenue=0&
  currency=USD

Common Postback Macros

Macro Description Example
{click_id} Ad network's click identifier ABC123
{app_id} App bundle ID / package name com.yourapp
{event_name} Conversion event name install, purchase, signup
{event_time} Event timestamp (Unix) 1720780200
{device_id} Device advertising ID (hashed) sha256_of_gaid
{idfa} iOS Identifier for Advertisers A1B2C3D4-...
{gaid} Google Advertising ID a1b2c3d4-...
{revenue} Revenue amount 9.99
{currency} Revenue currency USD
{campaign_id} Campaign identifier CAMP-789
{ad_group_id} Ad group identifier AG-456
{creative_id} Creative identifier CR-123
{country} Install country (ISO 3166) US
{os_version} Device OS version 17.5
{ip} User's IP address 203.0.113.42

Types of Postbacks

Install Postback

Fires when the app is installed and opened for the first time:

https://postback.adnetwork.com/install?
  click_id={click_id}&
  event=install&
  event_time={event_time}&
  device_id={device_id}

In-App Event Postback

Fires when the user completes a specific in-app event (purchase, registration, level completion):

https://postback.adnetwork.com/event?
  click_id={click_id}&
  event={event_name}&
  event_time={event_time}&
  revenue={revenue}&
  currency={currency}

Revenue Postback

A specialized in-app event postback that includes revenue data for ROAS (Return on Ad Spend) optimization:

https://postback.adnetwork.com/revenue?
  click_id={click_id}&
  event=purchase&
  revenue=49.99&
  currency=USD&
  product_id=premium_annual

Rejection Postback

Fires when an install claim is rejected (fraud, duplicate, wrong attribution):

https://postback.adnetwork.com/reject?
  click_id={click_id}&
  rejection_reason=fraud_detected&
  event_time={event_time}

Configuring Postback URLs

Setting Up a Postback

Each ad network provides its own postback URL template. You configure this in your attribution provider's dashboard:

{
  "network": "Ad Network A",
  "postback_url": "https://postback.adnetwork-a.com/conversion?click_id={click_id}&event={event_name}&revenue={revenue}",
  "events": ["install", "purchase", "registration"],
  "send_for": "attributed_only",
  "method": "GET"
}

Event Mapping

Map your in-app events to the ad network's expected event names:

Your Event Ad Network Event Postback
first_open install Install postback
registration_complete registration Event postback
first_purchase purchase Revenue postback
subscription_start subscribe Revenue postback
tutorial_complete tutorial Event postback

Building Your Own Postback System

If you are building attribution in-house, here is how to implement postback sending:

interface PostbackConfig {
  networkId: string;
  urlTemplate: string;
  events: string[];
  method: 'GET' | 'POST';
  retryPolicy: { maxRetries: number; backoffMs: number };
}

async function sendPostback(
  config: PostbackConfig,
  eventData: Record<string, string>
): Promise<void> {
  // Replace macros in URL template
  let url = config.urlTemplate;
  for (const [key, value] of Object.entries(eventData)) {
    url = url.replace(`{${key}}`, encodeURIComponent(value));
  }

  // Remove any unreplaced macros
  url = url.replace(/\{[^}]+\}/g, '');

  for (let attempt = 0; attempt <= config.retryPolicy.maxRetries; attempt++) {
    try {
      const response = await fetch(url, { method: config.method });

      if (response.ok) {
        console.log(`Postback sent to ${config.networkId}: ${response.status}`);
        return;
      }

      if (response.status >= 500) {
        // Server error, retry
        await sleep(config.retryPolicy.backoffMs * Math.pow(2, attempt));
        continue;
      }

      // Client error (4xx), don't retry
      console.error(`Postback failed for ${config.networkId}: ${response.status}`);
      return;
    } catch (error) {
      if (attempt < config.retryPolicy.maxRetries) {
        await sleep(config.retryPolicy.backoffMs * Math.pow(2, attempt));
      }
    }
  }

  console.error(`Postback to ${config.networkId} failed after ${config.retryPolicy.maxRetries} retries`);
}

Postback Validation

Verifying Incoming Postbacks

If you receive postbacks (e.g., from ad networks reporting click data), validate them:

function validatePostback(request: Request, networkSecret: string): boolean {
  // Check signature
  const signature = request.headers.get('X-Signature');
  const body = request.body;
  const expectedSignature = hmacSHA256(body, networkSecret);

  if (signature !== expectedSignature) {
    return false;
  }

  // Check timestamp freshness (prevent replay attacks)
  const timestamp = parseInt(request.url.searchParams.get('event_time') || '0');
  const now = Math.floor(Date.now() / 1000);

  if (Math.abs(now - timestamp) > 3600) {
    return false; // More than 1 hour old
  }

  return true;
}

Common Postback Failures

Issue Cause Fix
404 response Wrong postback URL Verify URL with ad network
Missing click_id Macro not replaced Check macro syntax matches provider's format
Duplicate postbacks Retry logic without dedup Add idempotency keys
Delayed postbacks Queue backlog Monitor queue depth, scale workers
Empty revenue Revenue macro not mapped Map revenue events correctly

Privacy and Postbacks

ATT and IDFA

On iOS, if the user has not consented to tracking via ATT, the IDFA is unavailable. Postbacks must use alternative identifiers:

  • SKAdNetwork postbacks: Apple sends postbacks directly to the ad network with campaign-level (not user-level) data.
  • Hashed identifiers: Some providers use hashed email or phone as an alternative identifier.
  • No identifier: Some postbacks omit device identifiers entirely and rely on the click_id alone.

GDPR

Under GDPR, sending user data (device IDs, IP addresses) to third-party ad networks requires a legal basis. Ensure your privacy policy covers this data sharing, and provide users with opt-out mechanisms.

Tolinku for Attribution Callbacks

Tolinku's webhooks can be used as postback URLs for deep link attribution events. When a user clicks a Tolinku deep link and converts, Tolinku can send a webhook to your server with the attribution data. Configure webhooks in the Tolinku dashboard.

For mobile attribution, see mobile attribution: a developer's guide. For the full install attribution flow, see install attribution flow: from ad click to first open.

Get deep linking tips in your inbox

One email per week. No spam.

Ready to add deep linking to your app?

Set up Universal Links, App Links, deferred deep linking, and analytics in minutes. Free to start.