# 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.

- 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.

Source: https://straitlink.in/docs/recipes/referral-invite-links/

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.

> **Referrals as a feature are a preview**
>
> A `referralCode` field, `?strait_ref=` on taps and a `referral.converted` webhook are built but not switched on yet. They're described on the [Referrals (preview)](https://straitlink.in/docs/referrals/) page. Nothing below depends on them.

## 1. Make one invite link per user

Put the user's invite code in the destination's query:

```bash
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](https://straitlink.in/docs/sdks/node/), when a user first opens their invite screen:

```js title="Node: invite-link.mjs"
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](https://straitlink.in/docs/recipes/batch-create-links/), 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

```bash
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:

```ts title="React Native: links.ts"
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](https://straitlink.in/docs/iphone-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:

```ts title="React Native: after signup"
links.trackEvent('signup'); // the invite tap is attached automatically
```

**You should see:** `trackEvent` resolve to `true`, and the signup in **Dashboard → Analytics** on the invite link's funnel.

## 5. Count invites per link

```bash
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 `referralCode` though you sent one.** That field is part of the [preview](https://straitlink.in/docs/referrals/), which isn't switched on. Keep the code in `longUrl`.

## Next steps

- [Referral and invite links](https://straitlink.in/solutions/referrals/): the flow at a glance, and what the preview adds.
- [Deferred deep linking](https://straitlink.in/docs/deferred-deep-linking/): how the destination survives the install.
