How to Connect CallRail to Google Sheets With n8n (No Add-On Required)
Pull CallRail calls into Google Sheets with a self-hosted n8n workflow: exact v3 API config, pagination, and the 429 rate-limit guard. Live in about an hour.
Edward Chalupa
Founder, Whtnxt · Dallas, TX
My plumber PPC guide documents the CallRail setup running on DFW home-service accounts. Every guide that ranks for “connect CallRail to Google Sheets” sells you a connector: a Zapier listing, a Supermetrics pitch, or CallRail’s aging Apps Script doc. This build owns the pull on self-hosted n8n, the pattern behind the Adtraction connector.
What are you actually building?
A scheduled n8n workflow that authenticates against the CallRail v3 API, pulls yesterday’s calls with date filters, flattens the JSON into one row per call, and appends the rows to a Google Sheet. You end up with a running log of every call: who rang, which tracking number answered, how long they talked, whether they hit voicemail, and which keyword brought them in.
The design choice that matters: pull with a date filter instead of paging through the full call history on every run. CallRail caps general API requests at 1,000 per hour and 10,000 per day, the default ceiling restated in Zapier’s CallRail integration notes, and a daily windowed pull uses two or three requests. That budget barely moves for one site, but I report a whole client roster from a single n8n instance, the same multi-account setup behind my marketing automation system build, so the window is what keeps the ceiling irrelevant.
This is the same reporting-pipe architecture I use for affiliate stats in Google Sheets and for the n8n reporting dashboards I deploy for clients. If you have never touched n8n, start with my n8n marketing automation engine setup before this build.
What do you need before you start?
| Item | Details | Time |
|---|---|---|
| CallRail account | Any plan; the API is not an add-on | Done already |
| API key | Account Settings > API Keys | 2 minutes |
| Account ID | From the URL when you log in to CallRail | 1 minute |
| n8n instance | Self-hosted or cloud | 20 minutes if new |
| Google Sheet | One tab, headers optional | 2 minutes |
| Google Sheets credentials | Service account with edit access to the sheet | 10 minutes |
Total: about 90 minutes from zero, under an hour if n8n already holds a working Google credential. CallRail itself costs $15 per month on the tracking number that my plumber cost breakdown itemizes, inside the stack described on the AI marketing automation page.
Step 1: Where do you get the API key and account ID?
In CallRail, open Account Settings and generate an API key. Copy it immediately; CallRail shows it once. Your account ID is the long number in the URL when you are logged in, the segment right after the site name. You need both for every request, and the key authenticates your whole account, so store it in the n8n credential vault rather than pasting it into nodes.
One warning from my first build: that key reads customer phone numbers and call recordings metadata across every company under the account. Treat it like a password. When I offboard a contractor who had n8n access, rotating the key took ninety seconds and instantly killed every old workflow, which is the correct behavior.
Step 2: How do you configure the HTTP Request node?
Add an HTTP Request node to a fresh workflow and configure it exactly like this:
- Method:
GET - URL:
https://api.callrail.com/v3/a/YOUR_ACCOUNT_ID/calls.json?start_date={{start}}&end_date={{end}}&per_page=250 - Authentication: Generic > Header Auth
- Header name:
Authorization - Header value:
Token token=YOUR_API_KEY
The auth format trips people up. CallRail does not use Bearer tokens or OAuth; the v3 API expects the literal word Token followed by token=, your key, and nothing else, the exact pattern in CallRail’s own API overview with sample requests. Keep the whole value inside the n8n credential so it never lands in the workflow JSON.
Info: The
per_pageparameter controls page size. CallRail’s pagination reference documents a default of 100 objects per page with a maximum of 250 on the calls endpoint, so one well-sized request covers a normal day for a single service company.
The date window is the second gotcha. The end_date parameter is inclusive of the day it names, and CallRail reads dates in your account’s configured time zone. My first version pulled “today” every morning, so it captured a partial day and missed the previous evening entirely. The fix was a one-day shift: yesterday morning to yesterday evening, run at 6 AM. Set the window in a small Set node before the request and reference it in the URL, and both problems disappear.
Step 3: How do you flatten the response into rows?
The API returns each call as a nested object with attribution data inside a sources array and the caller’s location split across several fields. The n8n Code node collapses that into flat rows. Return one item per call with the columns a service business actually reads:
call_id,start_time,durationcustomer_name,customer_phone_number,customer_city,customer_stateis_call_trackingand whether the call went to voicemailfirst_source(the top entry of thesourcesarray, which is the channel attribution)tracking_numberfromtracker_id
Keep call_id in the sheet even though it looks like junk. It is your dedupe key for the verification pass in Step 5, and CallRail re-sends some calls when tags change later in the week.
Info: Do not select every field the API offers. The single-call response carries waveform image URLs and page-view blobs that are useless in a spreadsheet and bloat the sheet. Ask for the fields you will filter on.
Step 4: How do you append rows to Google Sheets?
Add the Google Sheets node, set the operation to Append, and map the flattened rows to your header order. Two habits here save pain later. First, freeze the header row and never insert columns mid-sheet; an appended row silently shifts under a moved column and you will not notice for a month. Second, add a text column called run_date stamped with the workflow execution date. When a pull misfires, you can delete exactly the bad batch instead of untangling rows by hand.
Step 5: How do you schedule the pull and guard the rate limit?
Set a Schedule Trigger for 6:00 AM daily and activate the workflow. Now add the guard that separates a real pipeline from a demo. CallRail throttles excess traffic with the HTTP 429 status code, defined in its HTTP response codes reference as too many requests in a given amount of time. In n8n, turn on “Retry on Fail” in the HTTP Request node with three retries and a 60-second wait. If an account ever starts throwing 429s at 6 AM because a client migrated to an hourly pull, check the request count against the 1,000 per hour general-request ceiling restated in Zapier’s CallRail notes before you blame the workflow.
How do you verify the pipeline works?
Run the workflow manually once, then open the sheet and check four things:
- Row count roughly matches yesterday’s call count in the CallRail dashboard.
durationis in seconds and non-zero for connected calls.first_sourcenames a real channel (Keyword, PPC, Organic Listing) rather than sitting blank.- Running the workflow twice adds a second batch with the same
call_idvalues, confirming your dedupe key works before you rely on it.
If the numbers agree, leave the schedule on and check again after three days, because the weekend is where silent failures hide.
What breaks, and how do you fix it?
- 401 Unauthorized. CallRail’s response codes page ties a 401 to a missing valid API key, which in practice means your header value is wrong. It must be
Token token=with your key, notBearer, and no stray space. - Empty results on a day that clearly had calls. Check the time zone on the CallRail account, then widen the window by one day. A midnight-boundary mismatch causes most of these.
- Rows land in the wrong columns. The sheet gained or lost a column. Fix the mapping in the Google Sheets node rather than rearranging history.
- Only the first page of calls appears. Your window spans more rows than one page holds: CallRail’s pagination docs cap the calls endpoint at 250 records per page. Narrow the date window or walk the pagination fields in the response meta.
For the missed-call side of the same phone stack, the CallRail to Slack alert build covers the webhook half, and those two workflows share one API key and one n8n instance. If you would rather have the whole phone-to-CRM pipeline wired for you, the lead generation services page lists what I take on.
FAQ
Does CallRail have a native Google Sheets export? Not a live one. You can email reports and copy tables by hand, but there is no built-in sync. That gap is exactly what Zapier and Supermetrics sell subscriptions into, and it is why owning the pull on n8n beats renting it.
Can I pull call recordings into the sheet?
The list endpoint returns recording metadata, not the audio. Link the recording URL stored in CallRail by call_id and keep the audio inside CallRail, where its retention rules live.
Will this work for several client accounts?
Yes. One n8n instance can loop companies under a single CallRail account with the company_id filter, or hold one credential per account. My agency pull runs one workflow per client so a broken sheet never touches another account.
How is this different from a Zapier automation? Zapier charges per task forever and hides the request logic. I would rather own a workflow I can read than rent one I cannot audit: this build costs the slice of a VPS it runs on, and you control pagination, retry behavior, and the exact fields that land in the sheet. The same reasoning drives every paid search reporting stack I deploy.