Step 1 of 5Make the link on your server

Add a Share on WhatsApp button that opens your app

After this guide, a Share on WhatsApp button in your app sends a link made for that user and screen, the friend's tap opens the same screen in your app (or the store first), and the share is counted under WhatsApp.

  • Recipe
  • ~ 30 minutes
  • Android
  • iPhone
On this page 7
  1. 1. Make the link on your server
  2. 2. Check the chat preview and the tap
  3. 3. Open WhatsApp's share URL from the app
  4. 4. Read the sharer when the link opens the app
  5. 5. Count the shares
  6. Common errors
  7. Next steps
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 for Android and iPhone.

This is the share flow a user starts from your app. To send campaign messages from your business number instead, use WhatsApp Business API templates. Links need the secret key, which must never ship in an app, so the app asks your server for the link, then hands it to WhatsApp's share URL.

One link per user and screen, with the sharer in the destination's query:

Node: share-link.mjs
import { randomBytes } from 'node:crypto';
import express from 'express';
import { StraitClient } from '@straitlink/node';

const strait = new StraitClient({ apiKey: process.env.SECRET_KEY, baseUrl: 'https://strait.link' });
const app = express();
app.use(express.json());

// POST /share-link { "productId": "42" } → { "url": "https://…" }
// Put your own auth in front of this: req.user is the signed-in user.
app.post('/share-link', async (req, res) => {
  const productId = String(req.body.productId).replace(/[^\w-]/g, '');
  const userId = String(req.user?.id ?? 'guest').replace(/[^\w-]/g, '');
  const link = await strait.createLink({
    slug: `p${productId}-${randomBytes(4).toString('hex')}`,
    longUrl: `https://shop.example.com/product/${productId}?ref=${userId}`,
    title: 'Look what I found', // the preview card in the chat
    campaign: 'in_app_share',
  });
  res.json({ url: link.shortUrl });
});

app.listen(3000);

The same call with curl:

Terminal
curl https://strait.link/v1/links \
  -H "Authorization: Bearer $SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "slug": "p42-u7", "longUrl": "https://shop.example.com/product/42?ref=u7", "title": "Look what I found", "campaign": "in_app_share" }'

You should see: curl -X POST localhost:3000/share-link -H 'Content-Type: application/json' -d '{"productId":"42"}' answers {"url":"https://hilltop.strait.link/p42-…"} with a random ending, and the curl call answers "shortUrl": "https://hilltop.strait.link/p42-u7".

2. Check the chat preview and the tap

WhatsApp fetches the link to draw the preview card, and Strait answers its fetcher with the card, never a redirect. Check both without counting a tap:

Terminal
curl "https://strait.link/v1/simulate?url=https%3A%2F%2Fhilltop.strait.link%2Fp42-u7&ua=bot" \
  -H "Authorization: Bearer $SECRET_KEY"

curl "https://strait.link/v1/simulate?url=https%3A%2F%2Fhilltop.strait.link%2Fp42-u7&ua=whatsapp-android" \
  -H "Authorization: Bearer $SECRET_KEY"

You should see: "decision": "preview" for the bot, with a reason that says it is "counted as a preview, never billed". For whatsapp-android: "inAppBrowser": "whatsapp", "decision": "escape", and a location that starts intent://shop.example.com/product/42?ref=u7&strait_click=…, the one-tap Open in app button.

3. Open WhatsApp's share URL from the app

WhatsApp's own rule: "To create a link with just a pre-filled message, use https://wa.me/?text=urlencodedtext", and the person then picks who to send it to (WhatsApp Help Center).

React Native: ShareOnWhatsApp.tsx
import { Button, Linking } from 'react-native';

export function ShareOnWhatsApp({ productId }: { productId: string }) {
  async function share() {
    const res = await fetch('https://api.yourapp.com/share-link', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' }, // add your own auth header
      body: JSON.stringify({ productId }),
    });
    const { url } = await res.json();
    const text = `Look what I found: ${url}?utm_source=whatsapp`;
    await Linking.openURL(`https://wa.me/?text=${encodeURIComponent(text)}`);
  }
  return <Button title="Share on WhatsApp" onPress={share} />;
}

The ?utm_source=whatsapp on the shared URL labels the tap's channel even if the friend opens the link outside WhatsApp. Strait reads it there and doesn't copy it to the destination.

You should see: WhatsApp open with a contact list and the message filled in, ending in https://hilltop.strait.link/p42-…?utm_source=whatsapp. Opened in a browser, the wa.me URL answers 302 to https://api.whatsapp.com/send/?text=….

The destination's query arrives in e.params, on a direct open and on the first open after an install:

React Native: links.ts
links.onLink((e) => {
  if (e.matched && e.params?.ref) saveReferrer(e.params.ref); // your own code
});

On Android the destination travels through the Google Play install. On iPhone it comes back after an install when install matching is on.

You should see: a friend's tap opening the product screen, and e.params.ref set to u7, including on the first open after installing.

5. Count the shares

Terminal
curl "https://strait.link/v1/analytics?link=p42-u7&group=channel" \
  -H "Authorization: Bearer $SECRET_KEY"

In Node: await strait.getAnalytics({ link: 'p42-u7', group: 'channel' }). Leave out link and pass group=link to compare every shared link, or filter Dashboard → Analytics by the in_app_share campaign.

You should see: after a friend's tap, "rows": [{ "key": "whatsapp", "taps": 1, … }].

Common errors

  • 401 from Strait. The server sent the publishable key. Creating links needs a secret key, and the secret key stays on the server.
  • WhatsApp opens with an empty message. The text wasn't URL-encoded. Wrap it in encodeURIComponent, as above.
  • The preview card says "Open in" and your app's name. That's the default when the link has no description. Set description and imageUrl when you create the link.

Next steps