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.
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 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.
1. Make the link on your server
One link per user and screen, with the sharer in the destination's query:
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:
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:
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).
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=….
4. Read the sharer when the link opens the app
The destination's query arrives in e.params, on a direct open and on the first open after an install:
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
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
401from 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. SetdescriptionandimageUrlwhen you create the link.
Next steps
- Send campaign links via WhatsApp Business API templates: messages from your business number.
- Create links from a React Native app: the same server pattern with the system share sheet.