Add call tracking to an AI-built site
To add call tracking to an AI-built site, paste the Call Bullet script tag into the page head, mark your phone number, and the script swaps it for a number from your website pool per visitor. Each call is then matched to its source, keyword and landing page, readable from GET /workspaces/{id}/calls?include=attribution.
Last updated · Call Bullet
How does call tracking work on a website?
Call tracking shows each visitor a different phone number from a small pool, remembers where that visitor came from, and links the call back when they ring.
The Call Bullet script reads the visit's source, such as Google Ads, organic search or a social link, and keeps the click ID if there is one. It then replaces your phone number on the page with a pool number for that session. When the call arrives, Call Bullet knows which session held that number and attaches the source to the call. Read dynamic number insertion explained for the detail.
How do I install it step by step?
Installing takes about five minutes once your pool numbers are active.
- In Call Bullet, set up a website pool for the business; four to six numbers suit most small sites.
- Open Integrations → Website and copy your script tag. It contains an install key tied to this workspace.
- Ask your AI app builder to add the tag to the site's root page head, so it loads on every page.
- Show your main number as plain text or a tel: link anywhere on the page.
- Publish the site, open it in a private window and check the number changes.
- Ring the swapped number and confirm the call appears in Call Bullet with its source.
<script async src="https://callbullet.com/cb.js" data-cb-key="YOUR_INSTALL_KEY"></script>The install key is public by design: it can only swap numbers for this website, not read data. Your API key is different and must stay on the server.
Where should the script go in an AI-built app?
Put it in the shared root layout so every route loads it once, not inside a single page component. Single-page apps change routes without reloading, and the script watches the page for new phone numbers, so numbers rendered later are swapped too.
Keep the number in normal text or a tel: link. Numbers drawn inside images or canvas cannot be swapped. If your app uses cookie consent, load the script according to your consent setup.
How do I read the call sources back?
Request calls with attribution inline and group them by source in your dashboard.
import { cb } from "./call-bullet.server";
type Call = { id: string; started_at: string; answered: boolean; source: string | null; medium: string | null; campaign: string | null; keywords: string | null; landing_page_url: string | null };
export async function callsBySource(workspaceId: string) {
const from = new Date(new Date().getFullYear(), new Date().getMonth(), 1).toISOString();
const { data } = await cb<{ data: Call[] }>(
`/workspaces/${workspaceId}/calls?from=${from}&per_page=500&include=attribution&origin=call_bullet`,
);
const counts = new Map<string, number>();
for (const c of data) {
const key = [c.source ?? "direct", c.medium ?? "none"].join(" / ");
counts.set(key, (counts.get(key) ?? 0) + 1);
}
return [...counts].sort((a, b) => b[1] - a[1]); // [["google / cpc", 42], …]
}Which attribution fields will I get?
These fields are on each call when the visit was tracked.
| Field | Meaning |
|---|---|
| source / medium | Where the visitor came from, e.g. google / cpc |
| campaign / keywords | Ad campaign and keyword when captured |
| landing_page_url | The page they arrived on |
| referrer_url | The page that sent them |
| is_first_time_caller | First call from this number to this workspace |
| value_pence | Call value in pence, if set |
GET /calls/{id}/attribution returns the full visit evidence and a confidence level for a single call.
How many numbers do I need?
You need roughly one number per visitor on the site at the same time, plus a spare. A local trade with a few hundred visits a day usually needs four to six. If the pool runs out, visitors still see a working number but some calls cannot be matched to a session. Each number costs £5 a month; see session-based number pools for sizing.
What prompt do I paste into my AI app builder?
Use this to install the script and build a simple sources report.
Add Call Bullet call tracking to this website.
1. Add this tag once in the root layout <head> so it loads on every page: <script async src="https://callbullet.com/cb.js" data-cb-key="PASTE_MY_INSTALL_KEY"></script>
2. Make sure the business phone number is plain text or a tel: link (not an image).
3. Store my API key (cb_live_…, scopes workspaces:read, calls:read, attribution:read) as the server secret CALL_BULLET_API_KEY.
4. Add an admin page that calls GET /workspaces/{id}/calls?from=<start of month>&include=attribution&per_page=500 from the server and shows calls grouped by source / medium, with answered and missed counts.
5. Use only endpoints in https://callbullet.com/developers/api.md.How do I check it is working?
Open the site in a private window with ?utm_source=test on the URL and the number should change. Ring it from a mobile; within seconds the call appears in Call Bullet with source test. If the number does not change, check the tag is in the page head, the install key is correct, and the number on the page matches the business's main number set in Call Bullet.
How do I send website calls to Google Ads?
Connect Google Ads in Call Bullet, and calls from ad visitors are uploaded as conversions automatically; your app does not need to do anything extra.
The script stores the Google click ID when a visitor lands from an ad. When they ring, Call Bullet matches the call to that click and uploads it to Google Ads using the counting rules you choose, such as a minimum call length. You can read the delivery evidence with GET /integrations/google-ads/status to show a “sent to Google Ads” badge in your dashboard. See GCLID call tracking for how the match works.
What are the common installation mistakes?
Most problems come from where the tag is placed or how the number is written on the page.
- The tag is inside one page component instead of the root layout, so other pages never load it.
- The number on the page does not match the main number set in Call Bullet, so the script cannot find it to swap.
- The number is part of an image, a button graphic or a canvas, which cannot be changed.
- The site has a strict content security policy that blocks scripts from callbullet.com; add it to the allowed script sources.
- The website pool has only one or two numbers, so busy periods run out and some calls cannot be matched.
- The same tag is pasted twice, once in the layout and again on a page.
Can I show tracked numbers in my own dashboard?
Yes. Read the website pool with GET /workspaces/{id}/numbers and show each number's views and calls for the month.
For website pools, the views field reports website impressions, so you can show how often numbers were displayed next to how many calls they produced. A low call rate on a page with many views is a useful prompt to check the page's call to action. Combine it with the calls-by-source list above and your dashboard shows the full path from visit to phone call, for every channel, without leaving your app. Agencies can repeat the same view per client workspace, so every client sees which of their own pages and campaigns make the phone ring, using numbers they already own. Keep the API key on the server, cache the numbers list for a few minutes, and refresh the call counts on a schedule rather than on every page view, which keeps the dashboard fast.
Key takeaways
- One script tag in the root layout swaps numbers per visitor.
- Calls are matched to source, keyword and landing page.
- Read sources with GET /workspaces/{id}/calls?include=attribution.
- The install key is public; the API key stays on the server.
Frequently asked questions
Does the script slow my site?
It loads asynchronously, so the page renders first and the number swaps a moment later.
Does it work in single-page apps?
Yes. It watches for numbers that appear after route changes.
Will Google see the tracking number?
No. Your main number stays in the page source, so your business details stay consistent.
What if a visitor declines cookies?
Load the script according to your consent setup. Visitors who are not tracked still see a working number.
Can I track Google Ads calls too?
Yes. The script keeps the click ID so calls can be sent to Google Ads; see the Google Ads call tracking guides.
Is there a WordPress plugin?
Yes, for WordPress sites. For apps built with AI tools, the script tag is simplest.
See which marketing makes your phone ring
Start with one UK tracking number or a full website pool. Every call is recorded, transcribed and traced back to its source.