How to Track ig.me and m.me Link Referrals via API
Attribute Instagram and Messenger DM conversations to campaigns with ig.me/m.me ref parameters — referral webhooks, chat metadata, and replying before the first message.
What ig.me and m.me links are
https://ig.me/m/<username> (Instagram) and https://m.me/<page_username> (Facebook Messenger) deep-link a user straight into a DM thread with your business. Add a ref parameter and the link becomes trackable:
https://ig.me/m/your_username?ref=summer_promohttps://m.me/your_page?ref=qr-store-berlinref takes up to 2,083 characters of alphanumerics plus -, _, and = — enough to encode a campaign, a source, and a variant. Put a different ref on your bio link, each ad, each QR code, and every conversation tells you where it came from.
What Postproxy does with a referral
When a user enters the thread via such a link, Meta sends a referral event and Postproxy:
- finds or creates the chat for that participant,
- stores the referral on the chat —
metadata.referralholds{ "ref", "source", "type", "received_at" }(latest referral wins) andmetadata.last_referral_atis updated, - opens the 24-hour messaging window — per Meta policy a referral lets you reply free-form before the user sends anything,
- fires a
referral.receivedwebhook.
The referral is captured whether it arrives standalone (user opened the thread and hasn’t typed yet), embedded in the user’s first message, or inside an ice-breaker tap.
One Instagram-specific prerequisite: Meta only sends ig.me referrals for profiles that have at least one ice breaker set. No ice breakers, no referral events — so set them up first. m.me referrals on Facebook have no such requirement.
Handle the webhook
app.post("/webhooks/postproxy", async (req, res) => { res.sendStatus(200); // ack fast, work after
const event = req.body; if (event.type !== "referral.received") return;
const { chat, ref, source } = event.data.object;
// attribute the conversation await crm.tagConversation(chat.id, { campaign: ref, source });
// the referral opened the 24h window — greet before they even type await fetch(`https://api.postproxy.dev/api/chats/${chat.id}/messages`, { method: "POST", headers: { Authorization: `Bearer ${process.env.POSTPROXY_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ body: "Hey! Saw you came from the summer promo — want the discount code?", }), });});The payload carries the full chat object, the ref, Meta’s source (e.g. SHORTLINK), and type (e.g. OPEN_THREAD) — see the referral.received payload reference.
Greeting on every referral can feel aggressive for some audiences; the conservative variant is to store the attribution on the webhook and only use it when the user’s first message.received arrives.
Read attribution later
No webhook archaeology needed — the latest referral lives on the chat itself:
curl "https://api.postproxy.dev/api/chats/CHAT_ID" \ -H "Authorization: Bearer YOUR_API_KEY"{ "id": "chat_xyz789", "platform": "instagram", "metadata": { "referral": { "ref": "summer_promo", "source": "SHORTLINK", "type": "OPEN_THREAD", "received_at": "2026-06-10T12:00:00Z" }, "last_referral_at": "2026-06-10T12:00:00Z" }}If the same user later enters through a different link, the new referral overwrites metadata.referral — keep webhook events if you need the full history.
Rules and limits, in one place
| Rule | Value |
|---|---|
| Platforms | Instagram (ig.me), Facebook Messenger (m.me) |
| Instagram prerequisite | At least one ice breaker set on the profile |
ref format | ≤ 2,083 chars; alphanumerics, -, _, = |
| Stored at | chat.metadata.referral (latest wins) |
| Webhook | referral.received |
| Opens 24-hour window | Yes — reply before the first message |
| Arrival forms | Standalone, first message, ice-breaker tap |
Full details: ig.me / m.me link referrals in the Direct Messages reference. For the sending side of the conversation, see How to Send Instagram DMs via API and How to Send Facebook Messenger Messages via API.