How to Build an Invite Friends Feature for a Mobile App
Build an invite friends feature for a mobile app: a per-user referral link, the share sheet, the first launch, claimReferral, and a reward from a webhook.
To build an invite friends feature, give each user a referral link, share it from a button in the app, read the invitation on the friend's first launch, claim the install when the friend signs up, and grant the reward from a signed webhook. This guide builds each piece with code from the real API and SDKs.
You end with an invite button that opens the share sheet, a friend whose first launch knows who invited them, and a reward that arrives from your backend. The onboarding side, what the friend sees first, is covered in invite-a-friend onboarding. This post is the build.
What you are building
Four parts work together:
- A referral link per user. Your backend creates it and stores the id next to the user.
- An invite screen. A button that opens the share sheet with that link.
- The friend's first launch. The SDK reads the invitation, and the app claims the install after sign-up.
- A reward. Your backend receives a signed event that names the link and grants the credit.
The link is the first pillar, linking. The credited install is the second, attribution. The Referrals report, where you watch the results, is the third, analytics.
Step 1: Create a referral link per user
Create the link on your backend the first time a user opens the invite screen. The request needs an API key with the links:write scope. Keep that key on the server: an app that ships it hands every user the power to create links.
A slug derived from the user id with a server secret is stable, unguessable, and safe to retry. Save the returned id and short_url with the user. This example uses Node.js:
import { createHmac } from 'node:crypto';
const API = 'https://api.warplink.app/v1';
function slugFor(userId: string): string {
const digest = createHmac('sha256', process.env.INVITE_SLUG_SECRET!)
.update(userId)
.digest('hex');
return `invite-${digest.slice(0, 10)}`;
}
export async function inviteLinkFor(userId: string): Promise<string> {
const existing = await db.inviteLinks.findByUser(userId);
if (existing) return existing.shortUrl;
const response = await fetch(`${API}/links`, {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.WARPLINK_API_KEY}`,
'Content-Type': 'application/json',
'Idempotency-Key': `invite-link-${userId}`,
},
body: JSON.stringify({
app_id: process.env.WARPLINK_APP_ID,
slug: slugFor(userId),
destination_url: 'https://example.com/invite',
is_referral: true,
}),
});
if (!response.ok) throw new Error(`Link create failed: ${response.status}`);
const link = await response.json();
await db.inviteLinks.insert({ userId, linkId: link.id, shortUrl: link.short_url });
return link.short_url;
}
Three details matter:
is_referral: trueturns the link into a referral link. Only a link that belongs to an app can be one, so the request needs anapp_id. A tap from beforereferral_sinceon the link is never a referral.- The
Idempotency-Keyheader makes a retry safe. The same key and body returns the first response withIdempotent-Replayed: true, so a double tap on the invite button never creates a second link. A concurrent retry with the same key gets409 IDEMPOTENCY_IN_PROGRESS, so retry after a short wait. - The stored
idis how you find the inviter later. The webhook nameslink.id, and your table says whose link it is.
The same call runs from an assistant: the MCP create_link tool takes is_referral too. See the referrals guide for converting existing links in bulk.
Step 2: Add the invite screen and the share sheet
The app asks your own backend for the user's link, for example GET /me/invite, and shares the short_url it gets back. The system share sheet does the rest, so the user picks Messages, WhatsApp, or any other app.
SwiftUI
import SwiftUI
struct InviteView: View {
let inviteURL: URL
var body: some View {
ShareLink(item: inviteURL, message: Text("Join me on Acme. Tap to get the app.")) {
Label("Invite friends", systemImage: "person.badge.plus")
}
}
}
Android (Kotlin)
fun shareInvite(context: Context, inviteUrl: String) {
val send = Intent(Intent.ACTION_SEND).apply {
type = "text/plain"
putExtra(Intent.EXTRA_TEXT, "Join me on Acme. Tap to get the app: $inviteUrl")
}
context.startActivity(Intent.createChooser(send, "Invite friends"))
}
React Native
import { Share } from 'react-native';
export async function shareInvite(inviteUrl: string) {
await Share.share({ message: `Join me on Acme. Tap to get the app: ${inviteUrl}` });
}
Write the message the way a person would. A link with one plain sentence gets tapped more often than a link with a pitch. Flutter apps use the share_plus package for the same share sheet.
Step 3: Read the invitation on the friend's first launch
A friend who taps the link without your app goes through the store. Where the invitation goes next depends on the phone.
Android. Google Play hands the install referrer to the SDK at first launch, and the invitation rides inside it. You write no screen. The match is exact, with matchMethod set to android_referrer, and arrives in the onLink callback you already set up in Application.onCreate().
iPhone. An App Store install carries no data, so the friend sees a short invitation page before the store, which copies the invitation. On the first screen of your app, show the WarpLink paste button. The friend taps it once, with no permission prompt, and the SDK reads only the text that button hands over:
import SwiftUI
import WarpLink
@available(iOS 16.0, *)
struct WelcomeView: View {
@State private var message: String?
var body: some View {
VStack(spacing: 16) {
Text("Did a friend invite you?")
WarpLinkPasteButton { result in
switch result {
case .success(let link):
if link != nil { message = "Invitation applied." }
case .failure(let error):
message = error.localizedDescription
}
}
if let message { Text(message) }
Button("Skip") { continueOnboarding() }
}
}
}
Keep the Skip button. The paste step is an offer, not a gate. Show "Invitation applied" only when you get a link back. React Native and Flutter take pasted text from a field you provide and pass it to redeemInvitation. The full iPhone path is in make a referral link survive the App Store.
Step 4: Claim the install at sign-up
When the friend creates an account, tell WarpLink which of your users they are. You send an installer id: a dedicated random id for the new user, such as a UUID in its own column. It is up to 128 characters and never an email address or a phone number.
WarpLink.claimReferral(installerId: user.warplinkId) { result in
guard case .success(let claim) = result else { return }
switch claim.status {
case .claimed, .flagged:
break // recorded. Your webhook grants the reward.
case .ignored:
break // this installer already holds a credit
case .none:
break // no referral link brought this install
}
}
none is an ordinary answer: the friend arrived without an invitation, and nothing is recorded. The Kotlin, React Native, and Flutter calls have the same shape, and the quickstarts show each one. For rewards of value, send the claim from your backend with POST /v1/referrals/claims after your own checks pass.
Step 5: Grant the reward from the webhook
Add a webhook endpoint under Referral handoff, then Webhook. When the claim lands, we send a signed referral.claimed event. Verify the signature first, using the complete receiver in the Node.js webhook guide. Then map the link to the inviter and grant once:
async function onClaimed(event: ReferralEvent) {
const { referral_id, link, match } = event.data;
const inviter = await db.inviteLinks.ownerOfLink(link.id);
if (!inviter) return;
if (!match.exact) return db.holdForReview(referral_id);
await grantOnce(`${referral_id}:inviter`, inviter.userId);
}
Key the reward on referral_id. Delivery is at least once, so a retry or a resend can show you the same event twice, and the key stops a second grant.
Reward the inviter first. App Review text quoted by developers calls rewarding the inviter acceptable and objects to rewarding the person who installs, so read the App Store and Google Play referral reward rules before you add a friend-side bonus. For the checks worth adding before you pay, see verify a referral before you grant the reward.
Step 6: Test the whole path
- Delete the app from a test phone so the tap counts as a first install.
- Open the inviter's
short_urlon that phone, install, and open the app. - On iPhone, tap the paste button. On Android, nothing to tap.
- Sign up as a new test user with a new installer id and let
claimReferralrun. - Open Referral handoff, then Referrals, for the new row, and confirm your endpoint received the event.
The first valid claim for an app and installer id wins, so use a fresh installer id each run. How to test the install referrer and referral links covers Play internal testing and the test webhook.
Watch which invites work
Every invite link is an ordinary link with its own clicks, unique clicks, and installs. The Referrals report adds the credited installs, how each was matched, and the webhook result. The same list is GET /v1/referrals and the MCP tool list_referrals, so you can chart your top inviters in your own dashboard.
Frequently Asked Questions
How do I build an invite friends feature in a mobile app?
Create a referral link for each user from your backend, open the system share sheet with its short_url, read the invitation on the friend's first launch, call claimReferral when the friend signs up, and grant the reward from the signed referral.claimed webhook. Each step is a few lines of code.
Should the app or the backend create the invite link?
The backend. Creating a link needs an API key with the links:write scope, and that key must never ship inside an app. The app asks your own backend for the user's link and shares what it gets back.
Does the friend have to type a code?
No. The invitation travels with the link. On Android the SDK reads it from the Google Play install referrer with no screen of yours. On iPhone the friend taps one system paste button on the first screen.
Where does the reward come from?
Your backend grants it. We record the referral and send a signed referral.claimed event that names the invitation link. Your code looks up who owns that link and applies your own reward rules.
How do I know the invite feature works before I ship it?
Delete the app from a phone, open the inviter's link, install, sign up as a new test user with a new installer id, and check that the row appears in the Referrals report and the event reaches your endpoint.
Related Guides
- Reference: Referrals and the Referrals API.
- Onboarding side: Invite-a-friend onboarding and App referral programs.
- Stacks: React Native referral program, Flutter referral system, and Android install referrer referral code.
- Before you launch: A referral link checklist for launch.
- Choosing an approach: Best ways to add a referral program to a mobile app.
How WarpLink Helps
We carry the invitation through the store, credit the install to the link that brought it, and send your backend a signed event. The invite screen stays small because the hard part, proving which tap led to which sign-up, is already done.
One workflow, three pillars. Deep linking carries the invitation, install attribution credits the link that produced the new user, and real-time analytics shows referrals beside every other link. Sub-10ms redirects on the way in, one SDK on the way out.
Create a free WarpLink account and get deep linking, install attribution, and real-time analytics in one SDK, with 10,000 clicks a month on the free plan.
Try WarpLink on one real link
Deep linking, install attribution, and real-time analytics in one SDK. Free for 10K clicks a month, no sales call.
Stuck on setup? Email support@warplink.app and we will help you get one real link working.
WarpLink Team
Building affordable, reliable link infrastructure for mobile teams. Deep linking, install attribution, and real-time analytics in one SDK.
Related Posts
How to Test the Install Referrer and Referral Links
Test the Google Play install referrer and referral links before release: Play internal testing, adb checks, the iPhone paste path, and the test webhook.
Firebase Dynamic Links Migration Guide
Migrate Firebase Dynamic Links to WarpLink with a tested link inventory, domain cutover, SDK steps for four stacks, and checks for old links and analytics.
Android Install Referrer Referral Code in Kotlin
Pass a referral code through a Google Play install with the Play Install Referrer API in Kotlin, then let the WarpLink SDK read it and credit the inviter.