• Oct 13, 2026
  • 4 min read

A Google API Key vs a Service Account JSON: What Each One Unlocks

I already had a Google API key, for PageSpeed Insights. When I wanted Search Console data, my first question was whether that key would do. It wouldn’t, and the reason is the useful part: Google splits its APIs by whose data they return.

The rule

CredentialProvesUnlocksExample
API key (AIza…)“This project is calling”Public data; mostly for quota and billingPageSpeed Insights, Chrome UX Report
Service account key (JSON file)“This robot is calling, and an owner gave it access”Private data the robot was grantedSearch Console, Analytics, Drive
OAuth client ID”A person signed in and clicked Allow”That person’s private dataApps with “Sign in with Google”

Search Console data (your queries, clicks, indexing problems) belongs to the verified owner of a site. An API key carries no identity, so Google has no one to check permissions against. A service account is an identity, and you grant it access like you would a colleague.

For a script on my own machine or homelab, the service account is the right fit: no browser, no person clicking “Allow”, and access scoped to exactly the properties I add it to. The setup is in the step-by-step post.

What the API key did: PageSpeed Insights

The PageSpeed Insights API runs Lighthouse on Google’s machines and returns it, plus Chrome’s real-user data for the page when it exists:

curl -s "https://www.googleapis.com/pagespeedonline/v5/runPagespeed?url=https://www.example.com/&strategy=mobile&category=performance&key=$PSI_KEY"

The response has two halves:

  • lighthouseResult: a lab test (score, LCP, total blocking time, layout shift, and “opportunities” such as unused JavaScript).
  • loadingExperience and originLoadingExperience: the Chrome User Experience Report, meaning what real Chrome users experienced over 28 days. That includes INP, which only exists as real-user data. It’s what Google uses as a ranking signal.

I ran it over my seven sites in parallel. It found two things a local Lighthouse run hadn’t:

  1. The main site scored 81 on Google’s machines, with 0.9 s of unused JavaScript. The culprit was the Mermaid diagram library, loaded on every page including the homepage, which has no diagrams: 595 KB of a 994 KB JavaScript total. Importing it only when a diagram exists brought the score to 90 and LCP from 3.7 s to 2.9 s.
  2. No site had real-user data, including the blog that Cloudflare credits with about 2,600 visits a week. If those were real Chrome users, Google would very likely have enough data to report. Together with the countries behind that traffic, it pointed at bots.

It also produced one false alarm: “avoid multiple page redirects” on an app that only rewrites its address bar with history.replaceState. Nothing reloads; the test counts the changed URL as a redirect.

What the JSON key did: Search Console

With the service account added to each property, the same Python session could:

  • list properties and their permission level;
  • submit sitemaps, which revealed that two of my three domains had never had one submitted;
  • pull search data: 1 click and 93 impressions in 90 days, all for my own name;
  • inspect URLs one by one: 120 of 197 URLs on one domain were unknown to Google, and on the main site Google’s chosen canonical (/contact/) disagreed with mine (/contact), because every URL pointed at a redirect.

None of that is reachable with an API key.

Side by side

QuestionAPI key (PageSpeed)Service account (Search Console)
How fast is this page in a lab?YesNo
How fast is it for real Chrome users?Yes, if there’s enough trafficNo (the “Core Web Vitals” report is web-only)
Which searches show my site?NoYes
Is this URL indexed, and why not?NoYes
Submit a sitemapNoYes
Works for any public site?YesOnly sites you own

They’re complements, not alternatives: one is about speed, the other about being found.

Handling them

  • API key: restrict it in APIs & Services → Credentials to the one API it’s for. If it ends up in a chat, a screenshot or a commit, regenerate it. I passed mine on the command line for a one-off run and stored it nowhere.
  • JSON key: chmod 600, in a config folder outside every repository, never pasted anywhere. It’s a password for a robot.
  • Least privilege: the service account has no Cloud project roles at all. Its only power is the Search Console access it was given.

Takeaways

  • Public data, API key. Your private data, a service account (or OAuth if a person signs in).
  • PageSpeed answers “is it fast?”, Search Console answers “is it found?” You need both.
  • “No real-user data” is information. A site with real traffic but no Chrome UX Report data is probably being visited by bots.