Link Checker
Systematically validates all URLs across ads, keywords, and sitelinks by making HTTP requests and checking for error responses. Uses labels to track progress across runs, enabling large accounts to be checked in chunks without re-testing already-verified URLs.
by Google (original), chiliad (adaptation)·developers.google.com/google-ads/scripts/docs/solutions/link-checker
Overview
Link Checker fetches the final and mobile URLs of your ads, keywords, and campaign sitelinks and flags any that return an unexpected HTTP code (or whose page contains a failure string). Broken URLs are logged, emailed, and appended to an auto-created Google Sheet. A tracking label records which entities have been checked, so large accounts complete across multiple runs; once a full pass finishes the label is cleared and the next run starts fresh. It only adds/removes its own label — it never changes your ads.
Setup
- 1Create a new script and paste the code.
- 2Choose what to check: CHECK_ADS / CHECK_KEYWORDS / CHECK_SITELINKS, and whether to INCLUDE_PAUSED.
- 3Set VALID_CODES (e.g. 200, or 200,301,302); optionally set FAILURE_STRINGS to flag soft errors like Out of stock.
- 4Set EMAIL_ADDRESS to receive the report. Leave SPREADSHEET_URL blank on the first run to auto-create the report sheet — its URL is logged; paste it back to keep appending.
- 5Run the script (not preview) once so it can create its tracking label, then schedule it daily.
Configuration Variables
| Variable | Default |
|---|---|
CHECK_ADS | true |
CHECK_KEYWORDS | true |
CHECK_SITELINKS | true |
INCLUDE_PAUSED | false |
VALID_CODES | "200" |
Expected Output
BROKEN [404] https://example.com/old-page (Ad: Summer Sale) BROKEN [failure string: Out of stock] https://example.com/sku/123 (Keyword: running shoes) === Link Checker: 2 broken URL(s) this run === Emailed report to you@example.com All URLs checked — tracking label cleared; next run starts a fresh cycle.
Notes
The only write to your account is its own tracking label; URLs are never modified. ValueTrack parameters ({ifmobile:...}, {keyword}, etc.) are stripped before fetching. The failure-string check downloads each page, so it is slower — leave FAILURE_STRINGS blank to check HTTP codes only. Run the script (not preview) at least once so it can create the label.