Referral invite links that survive the install
After this guide, every user has an invite link, a friend who installs from it lands in your app with the invite code on the first open, and your server credits both people.
On this page 7
- Time
- About 30 minutes
- You need
- A backend you control with a Strait secret key as SECRET_KEY, and a React Native app with the Strait SDK set up
- Works on
- Server in Node 18+ (or curl). App code in React Native. Exact on Android through Google Play; on iPhone with install matching on.
This recipe uses only what works today: the invite code goes in the link's destination, and your app reads it from the link event. Strait doesn't grant rewards or hold credits; your server decides who gets what.
1. Make one invite link per user
Put the user's invite code in the destination's query:
curl https://strait.link/v1/links \
-H "Authorization: Bearer $SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{
"slug": "invite-a7k2",
"longUrl": "https://shop.example.com/invite?code=FRIEND10",
"title": "Asha sent you ₹100 off",
"campaign": "referral"
}'From your server with the Node SDK, when a user first opens their invite screen:
import { randomBytes } from 'node:crypto';
import { StraitClient } from '@straitlink/node';
const strait = new StraitClient({ apiKey: process.env.SECRET_KEY, baseUrl: 'https://strait.link' });
/** One invite link per user. Save the answer on the user's row and reuse it. */
export async function createInviteLink(user) {
const link = await strait.createLink({
slug: `invite-${randomBytes(3).toString('hex')}`,
longUrl: `https://shop.example.com/invite?code=${encodeURIComponent(user.inviteCode)}`,
title: `${user.firstName} sent you ₹100 off`,
campaign: 'referral',
});
return link.shortUrl;
}Use your own invite code or user id, never an email address or phone number: people share these links. For an existing user base, make the links with the batch API, 500 per call.
You should see: "shortUrl": "https://hilltop.strait.link/invite-a7k2" with "campaign": "referral". createInviteLink({ inviteCode: 'FRIEND10', firstName: 'Asha' }) returns https://hilltop.strait.link/invite- plus six hex characters.
2. Check that a tap carries the code to the app
curl "https://strait.link/v1/simulate?url=https%3A%2F%2Fhilltop.strait.link%2Finvite-a7k2&ua=android" \
-H "Authorization: Bearer $SECRET_KEY"In Node: await strait.simulateTap({ url: 'https://hilltop.strait.link/invite-a7k2', ua: 'android' }). No tap is counted.
You should see: "sentTo": "app_or_store" and a location that starts intent://shop.example.com/invite?code=FRIEND10&strait_click=…. Its Google Play fallback carries strait_link and strait_click in the install referrer, which is how the code survives the install.
3. Read the code in the app
The same onLink callback fires when the link opens an installed app and on the first open after an install:
links.onLink((e) => {
if (e.matched && e.path === '/invite' && e.params?.code) {
applyInviteCode(e.params.code); // "FRIEND10": send it to your server
}
});On Android, a friend without the app goes through Google Play, and the first open gets the code exactly. On iPhone the first open after an App Store install gets it when install matching is on; without it, that first open has no code.
You should see: with the app installed, a tap on https://hilltop.strait.link/invite-a7k2 opens the app and applyInviteCode gets FRIEND10. After a Play install from the same link, the first open gets it too.
4. Credit both people on your server
Your server receives the code from the app, checks it belongs to a real user and isn't the new user's own, then grants the reward. To see signups next to the invite taps in Analytics, record an event from the app once the account exists:
links.trackEvent('signup'); // the invite tap is attached automaticallyYou should see: trackEvent resolve to true, and the signup in Dashboard → Analytics on the invite link's funnel.
5. Count invites per link
curl "https://strait.link/v1/analytics?link=invite-a7k2&group=channel" \
-H "Authorization: Bearer $SECRET_KEY"In Node: await strait.getAnalytics({ link: 'invite-a7k2', group: 'channel' }). Without UTM tags, a tap is labelled by the app it was opened in (whatsapp, instagram…) or direct.
You should see: after a tap from a phone's browser, "rows": [{ "key": "direct", "taps": 1, "billableTaps": 1, "appOpens": 0, "installs": 0, … }]. appOpens and installs grow as friends open the app from the link.
Common errors
409"slug already exists in this workspace". Two users got the same slug. Keep the random part, or retry with a new one.- iPhone friends don't get the code after installing. Install matching is off. Switch it on in Settings → iPhone installs, or show a field for the code as a fallback.
- The answer has no
referralCodethough you sent one. That field is part of the preview, which isn't switched on. Keep the code inlongUrl.
Next steps
- Referral and invite links: the flow at a glance, and what the preview adds.
- Deferred deep linking: how the destination survives the install.