Set up Dynamic Number Insertion
Who this is for: Engineers and marketers instrumenting landing pages so inbound calls can be attributed to campaigns and ad clicks. What you’ll need: Access to Integrations → Snippets and Numbers → Number Pools, plus the ability to edit the landing page markup. Time required: About 30 minutes, plus site deploy time.
What DNI does
Section titled “What DNI does”Dynamic Number Insertion replaces the phone number shown on your website with a Moja tracking number drawn from a number pool, and ties that number to the visitor’s session. When the visitor calls, Moja can connect the call back to the landing page, the traffic source, the UTM parameters, and the ad click that brought them there.
Without DNI, a website call is tracked as a call but carries no visitor-session context. A static number tells you the phone rang. DNI tells you which ad made it ring.
The same session context powers conversion uploads to connected ad platforms. For Google Ads the snippet captures gclid, gbraid, or wbraid; for Meta it can capture fbclid, _fbc, and _fbp.
The pieces
Section titled “The pieces”| Piece | What it does | Where it lives |
|---|---|---|
| Tracking tag / snippet | JavaScript on the landing page that captures visitor-session data | Integrations → Snippets |
| Number pool | The group of tracking numbers available for dynamic assignment | Numbers → Number Pools |
| Session attribution | Connects the call to UTM parameters, referrer, browser data, and click IDs | Reporting / Call Tracking |
| Cross-domain tracking | Keeps the visitor ID intact when visitors move between your domains | Edit Snippet → Linked Domains |
Snippet configuration fields: Snippet Name, Campaign (Default) Number, Number to Replace, Number Pool, Linked Domains.
How it works end to end
Section titled “How it works end to end”- A visitor lands on the page from an ad, search result, referral, or email.
- The snippet loads and captures session data — UTM parameters, referrer, browser data, and supported click identifiers.
- DNI selects a number from the configured pool and replaces the target number on the page.
- The visitor calls the inserted number.
- Moja ties the call back to that visitor session.
- Reporting and connected integrations use the attribution.
Before you begin
Section titled “Before you begin”- Decide which static number on the page should be replaced, and which numbers should stay static.
- Estimate concurrent landing-page traffic so you can size the pool.
- For paid traffic, enable Google Ads auto-tagging so click identifiers reach the landing page.
Set it up
Section titled “Set it up”-
Create or confirm a number pool.
Go to Numbers → Number Pools. Create a pool or select an existing one, choose the number type and pool size for expected traffic, and confirm the numbers are provisioned and available.
Expected result: the pool shows provisioned, available numbers.
-
Create or edit the snippet.
Go to Integrations → Snippets. Set a clear Snippet Name, select the Campaign (Default) Number, enter the Number to Replace exactly as it appears on the site, select the Number Pool, and turn on Enable Number Replacement. Configure Linked Domains if visitors move across your domains.
Expected result: the snippet saves with a pool attached and replacement enabled.
-
Install the snippet on the page.
Copy the snippet code from Moja and paste it into the
<head>of every landing page that should use DNI, then publish. Load the page and confirm the number on screen is a Moja tracking number.Expected result: the displayed number differs from your static number and changes across fresh sessions.
-
Test attribution.
Visit the landing page with test tracking parameters on the URL, confirm the number was replaced, place a test call, then open the call in Moja and confirm the attribution data is attached.
Expected result: the call record shows the tracking identifiers and campaign context from your test URL.
Pool behaviour
Section titled “Pool behaviour”A number pool gives each visitor session its own trackable number. The pool has to be large enough that concurrent visitors do not collide.
Moja sends a one-time warning when a pool reaches 85% utilization. It will not warn again for that pool until utilization drops below 85% and later crosses the threshold again. When you get the warning, add numbers or release ones you no longer need. Running a pool near capacity risks fallback behaviour and the loss of visitor-level attribution.
Pool numbers vs static numbers
Section titled “Pool numbers vs static numbers”| Static number | Pool number via DNI | |
|---|---|---|
| Attribution | Call is tracked, but usually carries no visitor-session context | Call is tied to the session, source, UTMs, and click IDs |
| Assignment | Same number for everyone | A number from the pool per visitor session |
| Sizing | One number | Sized to concurrent traffic; needs headroom |
| Ad-platform conversion uploads | Not reliably supported | Supported when click identifiers were captured |
Existing static numbers keep receiving and tracking calls. DNI only affects pages where the snippet is installed and configured to replace a number.
Verify it works
Section titled “Verify it works”- The displayed number changes from your static number when the snippet is live.
- A fresh browser session gets a number from the pool.
- Your test call appears in Reporting / Call Tracking with attribution attached.
- Useful labels to look for: Tracking IDs, WITH GCLID / Click ID, CONVERSIONS, UPLOADED, and Conversion Value / Type.
Common failure modes
Section titled “Common failure modes”| Symptom | Likely cause | Fix |
|---|---|---|
| Number is not replaced | Snippet not in the page <head>, Enable Number Replacement off, or Number to Replace does not match the number on the page |
Check all three, then retest in a fresh browser session with cache cleared |
| Number is not replaced, config looks right | Pool has no available numbers | Check pool utilization and add numbers |
| Wrong number replaced | Number to Replace matches more than one number on the page | Narrow the value; confirm which numbers should stay static |
| Call tracked but attribution missing | Visitor dialed a static number, or the snippet had not loaded before they called | Confirm the dialed number came from the pool and that the snippet loads early in <head> |
| Attribution missing across domains | Visitor moved between domains and the visitor ID was not carried | Configure Linked Domains |
| UTMs missing on the call | Landing page URL dropped the query string, often via a redirect | Confirm parameters survive every redirect hop |
| Google Ads conversions not uploading | No gclid, gbraid, or wbraid on the call |
Enable Google Ads auto-tagging and confirm the snippet is on every paid landing page |
| Meta conversions not uploading | fbclid, _fbc, or _fbp not captured |
Confirm the landing page can capture Meta identifiers and that the integration is connected |
| Attribution degrades under traffic spikes | Pool at or near capacity, triggering fallback | Raise pool size ahead of campaign launches |
Related
Section titled “Related”- Webhooks — the
[GCLID],[UTM_SOURCE], and visitor tags are populated for DNI calls - Developers
- DNI, tracking tags/snippets, and number pools
- Google Ads integration: conversion postbacks with snippets and DNI
- Track affiliate IDs with DNI on shared landing pages
- Meta Ads integration: send call conversions to Meta Conversions API

