Skip to content

Server-to-Server Impressions ​

Report ad impressions from your server so Linkrunner can credit view-through installs

When to use S2S impressions ​

A click link only credits users who tap your ad. Many users see an ad, don't tap it, and install the app later from the store. Without impression data, those installs look organic.

Your server reports each impression (the ad was shown) to Linkrunner. If the same device installs the app within the view-through window and there is no click to credit, Linkrunner credits the install to your impression. This is view-through attribution. It works like impression tracking in AppsFlyer and accepts the same parameter names.

Every S2S request must carry your partner token. See Authenticate your requests.

View-through is off by default. The advertiser turns on S2S traffic and view-through for each partner separately, and sets your view-through window. Ask them, or Linkrunner support, before you send impressions. Until then, requests are rejected with partner_not_enabled or view_through_disabled.

How it works ​

Ad is shown to the user
      │
      │ your server, in real time
      ▼
GET s2s.linkrunner.io/v1/impression/<app_id>
      │
      │ later, the user installs and opens the app (no click)
      ▼
Linkrunner matches the install to your impression by GAID / IDFA
      │
      ▼
Install postback to your endpoint ({touch_type} = impression)

Linkrunner credits an impression only when all of these hold:

RuleDetail
Device ID matchThe impression carries the same gaid (Android) or idfa (iOS) as the installing device. IP is never used for view-through.
No click winsAny click from any source that can be credited, including an IP match, wins over every impression.
Inside the windowThe install happens within the view-through window after the impression. The advertiser sets it for you, from 1 to 24 hours (24 by default). Your vt_lookback can shorten it, never lengthen it.
Latest impressionIf several impressions match, the most recent one inside its own window is credited. Each impression is credited to at most one install.

Postbacks work as for clicks. Your postback templates, event mapping and postback logs apply unchanged, and {touch_type} is impression for view-through installs.

Set it up ​

Get your S2S token

If you already send S2S clicks, use the same token and skip this step.

Otherwise, in your affiliate dashboard, open Settings → S2S Credentials and click Generate token. Copy the token (it starts with lrs2s_) and store it as a secret on your server. It is shown only once.

Start from your campaign link

Create the link in your affiliate dashboard as usual. See Create a campaign link. You get a tracking link like this:

https://app.example.com/?c=OgWmhiSXhG&tid={click_id}&s2={campaign_id}

Turn it into the impression URL

Keep your parameters, and send them to https://s2s.linkrunner.io/v1/impression/<app_id>. <app_id> is the app's Android package name (com.example.app) or its App Store ID (id1234567890).

Then add the device ID (gaid or idfa, required), the time of the impression, and optionally a shorter view-through window. Your token goes in the X-Linkrunner-Token header:

http
GET https://s2s.linkrunner.io/v1/impression/com.example.app?c=OgWmhiSXhG&tid={impression_id}&s2={campaign_id}&gaid={gaid}&impression_time={timestamp_ms}&vt_lookback=24h
X-Linkrunner-Token: <your_token>

tid is your ID for this impression. Use a value that is unique per impression, not your click ID.

You can name the advertiser by the tracking link's domain instead: https://s2s.linkrunner.io/v1/impression?d=app.example.com&c=.... Use d if the advertiser's test and live apps share an app ID and the same campaign code.

Fire it from your server when the ad is shown

Replace your macros and call the URL with GET and the token header when the impression happens. A 200 with "status":"accepted" means the impression is recorded. See retries for the other responses.

Test it end to end

Send one impression with the GAID of a test device. Don't tap any ad on that device. Install and open the app within the window. The install postback arrives with your tid and {touch_type} = impression. Check it in Postback logs.

Send each impression as it happens. An impression that arrives after the install can't be credited, and impressions older than 24 hours are rejected.

Authenticate your requests ​

Linkrunner rejects any S2S request that doesn't carry your partner token, with 401 and missing_token or invalid_token. The token proves the traffic comes from you, so nobody else can send impressions in your name.

Send it in the X-Linkrunner-Token header on every request. This example reads it from the LINKRUNNER_S2S_TOKEN environment variable:

bash
curl -G "https://s2s.linkrunner.io/v1/impression/com.example.app" \
  -H "X-Linkrunner-Token: $LINKRUNNER_S2S_TOKEN" \
  --data-urlencode "c=OgWmhiSXhG" \
  --data-urlencode "tid=imp-7f3a91" \
  --data-urlencode "gaid=38400000-8cf0-11bd-b23e-10b96e40000d"

If your ad server can only fire a URL and can't set headers, add the token as the lr_token query parameter instead:

text
https://s2s.linkrunner.io/v1/impression/com.example.app?lr_token=<your_token>&c=OgWmhiSXhG&tid={impression_id}&gaid={gaid}

Linkrunner removes lr_token before it stores the impression, so the token never appears in reports or postbacks. Use the header when you can, because full URLs often end up in server logs.

Your token is valid for every app you're connected to, for both S2S impressions and S2S clicks.

Rotate or revoke your token ​

Manage your token in Settings → S2S Credentials.

  • Rotate: generate a new token. Your previous token keeps working for 24 hours, so update your servers within that time. If you rotate again within those 24 hours, your older token keeps its original expiry, and the token from your last rotation stops working right away.
  • Revoke all: stops every token at once. All your S2S requests are rejected until you generate a new token and send it.

New, rotated and revoked tokens take up to a minute to apply.

Treat the token like a password. Don't put it in client apps, public repositories or tracking links you share. If it leaks, use Revoke all and then generate a new token. Rotating alone keeps the leaked token working for 24 hours.

Coming from AppsFlyer ​

If you already send impressions to AppsFlyer, you can reuse that template. You change the host and c, and add your token.

AppsFlyerLinkrunnerNotes
impression.appsflyer.com/<app_id>s2s.linkrunner.io/v1/impression/<app_id>The same app ID: Android package name or App Store ID
c (campaign name)c (campaign code)Use the c value from your Linkrunner tracking link, not a campaign name
clickidtidEither name works. Send a unique ID per impression
advertising_idgaidEither name works
idfaidfaSame
af_viewthrough_lookbackvt_lookbackEither name works. 1h to 24h, or 1d. Longer values are capped at 24 hours
af_ip, af_uaip, uaEither name works. Stored, never used for matching
af_sub1, af_sub2, af_sub3s2, s3, s4Either name works. Returned in {s2} to {s4}
pid, af_siteid, af_langNot neededIgnored if present

An AppsFlyer template like this:

https://impression.appsflyer.com/com.example.app?pid=xyz_int&c=summer&clickid={impression_id}&advertising_id={gaid}&af_viewthrough_lookback=24h&af_sub1={pub}

becomes:

http
GET https://s2s.linkrunner.io/v1/impression/com.example.app?c=OgWmhiSXhG&clickid={impression_id}&advertising_id={gaid}&af_viewthrough_lookback=24h&af_sub1={pub}
X-Linkrunner-Token: <your_token>

Retries ​

Retrying is safe. The same tid for the same campaign always returns the same impression_id and is stored once.

  • Retry 429 and 503, after the Retry-After delay.
  • Don't retry other 4xx responses. Fix the request instead. The reason tells you what's wrong.

See the S2S Impression API reference for every parameter, response and rejection reason.

Troubleshooting ​

Requests return missing_token. The request has no X-Linkrunner-Token header and no lr_token parameter. Check that your server or ad platform sends the header on every call, not only on some of them.

Requests return invalid_token. The token is wrong, was revoked, or was replaced more than 24 hours ago. You also get this while your partner account is suspended. Copy the current token from your server's secret store, not from an old template. If you no longer have it, rotate it in Settings → S2S Credentials.

Requests return missing_device_id. Impressions need a gaid or idfa. Unlike S2S clicks, an IP address alone is not enough. An all-zero ID counts as missing.

Requests return partner_not_enabled or view_through_disabled. The advertiser hasn't turned on S2S traffic, or view-through, for your partner account on this app. Changes take up to 5 minutes to apply.

Requests return impression_too_old.impression_time is more than 24 hours ago. Send impressions as they happen.

Requests return invalid_viewthrough_lookback. Use whole hours (6h, 24h, or 6) or 1d. Fractions, weeks and 0 are rejected.

Impressions are accepted but installs aren't credited to them. Check that the impression carries the user's real GAID or IDFA and arrives before the install. A click from any source, or a more recent impression, takes priority. The install must also fall inside the view-through window the advertiser set for you.

Need help? Contact support@linkrunner.io