Paid ads links that open your app
After this guide, your ads point at Strait links that open the right screen in your app, you know what a tap from Instagram's or Facebook's browser does, and each tap is counted under the ad platform you name.
On this page 6
- Time
- About 20 minutes
- You need
- A Strait secret key in your server's environment as SECRET_KEY, and an ad account on the platform you advertise with
- Works on
- Any server. Code for curl and Node 18+. The links work for Android and iPhone users and on computers.
Use a Strait link as the ad's URL when the ad should open your app, or the store and then the app after an install. Put the UTM tags on the link's destination. Two things behave differently from a plain landing page URL: taps inside Instagram's or Facebook's own browser get a page with an Open in app button, and tracking ids the ad platform adds to the link, like gclid or fbclid, are not copied to the destination.
1. Make one link per platform and campaign
curl https://strait.link/v1/links \
-H "Authorization: Bearer $SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{
"slug": "diwali-ads",
"longUrl": "https://shop.example.com/sale/diwali?utm_source=instagram&utm_medium=paid_social&utm_campaign=diwali-2026-ads"
}'The same with the Node SDK, with the in-app browser check from step 2:
import { StraitClient } from '@straitlink/node';
const strait = new StraitClient({ apiKey: process.env.SECRET_KEY, baseUrl: 'https://strait.link' });
const link = await strait.createLink({
slug: 'diwali-ads',
longUrl: 'https://shop.example.com/sale/diwali?utm_source=instagram&utm_medium=paid_social&utm_campaign=diwali-2026-ads',
});
for (const ua of ['instagram-android', 'instagram-ios', 'facebook-android']) {
const tap = await strait.simulateTap({ url: link.shortUrl, ua });
console.log(ua, tap.decision, tap.sentTo);
}You should see: "shortUrl": "https://hilltop.strait.link/diwali-ads" and "campaign": "diwali-2026-ads", filled in from utm_campaign.
2. Check what a tap in the ad platform's browser does
Instagram and Facebook usually open ad links in their own in-app browser, where apps and stores often don't open. GET /v1/simulate shows what Strait does there, without counting a tap:
curl "https://strait.link/v1/simulate?url=https%3A%2F%2Fhilltop.strait.link%2Fdiwali-ads&ua=instagram-android" \
-H "Authorization: Bearer $SECRET_KEY"
curl "https://strait.link/v1/simulate?url=https%3A%2F%2Fhilltop.strait.link%2Fdiwali-ads&ua=instagram-ios" \
-H "Authorization: Bearer $SECRET_KEY"facebook-android is a preset too. Open apps from Instagram explains the in-app browser in more detail.
You should see: "inAppBrowser": "instagram", "decision": "escape" and "sentTo": "in_app_browser_page" for both. On Android the location is an intent:// link that opens the app, or Google Play without it, and the reason says the page has a one-tap Open in app button. On iPhone the reason says the page explains how to open the link in the real browser. The Node script prints escape in_app_browser_page three times.
3. See what happens to gclid and fbclid
Google Ads auto-tagging adds a gclid to the ad's URL, and Google asks that, with redirects, "the GCLID is passed to the final landing page in order to track conversions" (Google Ads Help: About auto-tagging). Strait sends each tap to the destination saved on the link and doesn't copy query parameters from the tapped URL. Check it with one real tap from a desktop browser user agent (this counts as one tap):
curl -s -o /dev/null -D - \
"https://hilltop.strait.link/diwali-ads?gclid=TEST456&fbclid=TEST123&utm_source=meta" \
-A "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0 Safari/537.36"So if you measure web conversions with gclid, point those ads at your landing page directly, and use Strait links for the ads that should open the app. The utm_source on the tapped URL is still read: it names the tap's channel and wins over the destination's.
You should see: HTTP/2 302 and location: https://shop.example.com/sale/diwali?utm_source=instagram&utm_medium=paid_social&utm_campaign=diwali-2026-ads, with no gclid or fbclid.
4. Read the taps per channel
curl "https://strait.link/v1/analytics?link=diwali-ads&group=channel" \
-H "Authorization: Bearer $SECRET_KEY"In Node: await strait.getAnalytics({ link: 'diwali-ads', group: 'channel' }). Without a utm_source on the tapped URL, taps count under the destination's utm_source, here instagram. To split one link across platforms, add ?utm_source=meta or ?utm_source=google to the URL you paste into each ad manager.
You should see: after the tap in step 3, "rows": [{ "key": "meta", "taps": 1, "billableTaps": 1, … }], because that tap carried utm_source=meta.
Common errors
- Web conversions from Google Ads drop after you switch to a Strait link. The
gclidstops at the link (step 3). Keep web-conversion ads on your landing page URL. - Ad taps count as
instagramwhen you wantedmeta. The destination'sutm_sourceis used when the tapped URL has none. Add?utm_source=metato the URL in the ad, or change the destination withPATCH /v1/links/{slug}. - Instagram users on iPhone land on a page instead of the app. That's the in-app browser page from step 2: it explains how to open the link in the real browser, where the app can open.
Next steps
- Email campaign links that open your app: the same UTM pattern for newsletters.
- Analytics: how we count: what counts as a tap, an install and an open.