Skip to content

feat(ahrefs): validate integration, fix cents/column bugs, add 13 v3 endpoints#5447

Merged
waleedlatif1 merged 8 commits into
stagingfrom
feat/ahrefs-integration
Jul 6, 2026
Merged

feat(ahrefs): validate integration, fix cents/column bugs, add 13 v3 endpoints#5447
waleedlatif1 merged 8 commits into
stagingfrom
feat/ahrefs-integration

Conversation

@waleedlatif1

Copy link
Copy Markdown
Collaborator

Summary

  • Audited the existing Ahrefs integration against live Ahrefs API v3 docs
  • Fixed broken_backlinks selecting the wrong column (http_code_target instead of http_code), which broke the httpCode output on every row
  • Fixed keyword_overview, metrics, and metrics_history returning CPC/cost fields in USD cents without converting to USD (values were 100x too high)
  • Fixed the Top Pages operation's mode dropdown missing the exact option
  • Added 13 new tools for previously-unsupported Ahrefs v3 endpoints: Rank Tracker (overview, SERP overview, competitors overview, competitors stats), Batch Analysis, Site Audit page explorer, 4 history/trend endpoints (domain rating, metrics, referring domains, keywords), Related Terms, Anchors, and Paid Pages
  • Renamed an output key collision between two operations (ahrefs_organic_keywords and ahrefs_rank_tracker_competitors_overview both used keywords with incompatible shapes) — the latter is now competitorKeywords

Note on backwards compatibility

The CPC/cost unit fix is a silent 100x value change for organicCost/paidCost/cpc on any existing workflow already consuming those fields — the old values were wrong (in cents, not dollars). Everything else is additive; no existing tool ids, subBlock ids, or output keys were removed or renamed.

Type of Change

  • Bug fix
  • New feature

Testing

Tested manually — validated every tool's endpoint, params, and response mapping against live Ahrefs v3 docs across three independent verification passes (fresh docs re-check of all 13 new tools, full block-wiring cross-check, backwards-compat diff review). bun run lint, bun run type-check, and bun run check:api-validation all pass clean.

Checklist

  • Code follows project style guidelines
  • Self-reviewed my changes
  • Tests added/updated and passing
  • No new warnings introduced
  • I confirm that I have read and agree to the terms outlined in the Contributor License Agreement (CLA)

…endpoints

Audited the existing Ahrefs integration against live API v3 docs and fixed
real bugs: broken_backlinks selected the wrong column (http_code_target
instead of http_code), and keyword_overview/metrics/metrics_history returned
CPC/cost fields in USD cents without converting to USD. Also fixed the
top-pages mode dropdown missing the "exact" option.

Added 13 new tools covering previously-unsupported Ahrefs v3 endpoints:
Rank Tracker (overview, SERP overview, competitors overview, competitors
stats), Batch Analysis, Site Audit page explorer, four history/trend
endpoints (domain rating, metrics, referring domains, keywords), Related
Terms, Anchors, and Paid Pages.

Note: the CPC/cost unit fix silently shifts existing organicCost/paidCost/cpc
values by 100x for any workflow already consuming them (the old values were
wrong, in cents instead of dollars).
@vercel

vercel Bot commented Jul 6, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
docs Skipped Skipped Jul 6, 2026 10:54pm

Request Review

@cursor

cursor Bot commented Jul 6, 2026

Copy link
Copy Markdown

PR Summary

Medium Risk
Existing workflows using cpc/organicCost/paidCost will see ~100x lower values (intentional fix from cents). Large new API surface increases maintenance and misconfiguration risk with project IDs and API keys.

Overview
Expands the Ahrefs integration from 10 to 23 workflow operations by wiring 13 new Ahrefs API v3 tools (paid pages, anchors, related terms, four history endpoints, batch analysis, Site Audit page explorer, and four Rank Tracker endpoints) through the block UI, tool registry, types, and integration metadata/docs.

Bug fixes and polish: CPC and cost-style fields (cpc, organicCost, paidCost, traffic value, etc.) now divide API cents by 100 so outputs are in USD. Top Pages gains shared exact analysis mode via MODE_OPTIONS, and docs drop “planned” labels for organic keywords/top pages.

The Ahrefs block adds operation-specific inputs (date ranges, projectId, device, batch targets, pagination) and maps UI fields like crawlDate/asOfDate to API date. New workflow templates cover Rank Tracker digests, batch competitor snapshots, and Site Audit issue tracking. Rank Tracker competitors overview exposes competitorKeywords as a distinct output shape from organic keywords.

Reviewed by Cursor Bugbot for commit b1b5611. Configure here.

httpCode: page.http_code ?? null,
title: page.title ?? [],
internalLinks: (page.internal_links || []).length,
externalLinks: (page.external_links || []).length,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Link counts use array length

Medium Severity

In ahrefs_site_audit_page_explorer, internalLinks and externalLinks are derived with (page.internal_links || []).length and the same for external links, while backlinks on the same row is taken as a numeric field. If the API returns link counts as integers (consistent with backlinks), non-zero counts become undefined because numbers have no .length, so workflows see missing or wrong link metrics.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 934dca7. Configure here.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Checked this directly against the live Ahrefs v3 docs raw JSON schema for GET /v3/site-audit/page-explorer:

"internal_links":{"items":{"type":"string","format":"url"},"type":"array","title":"internal_links","description":"The list of internal outgoing links on the page"}

Same shape for external_links. Both fields are genuinely documented as array<string (url)> (lists of the actual outgoing link URLs), not integer counts — Ahrefs also exposes separate dedicated count fields for this (links_count_internal, links_count_external), which are integers, but those are not what this tool selects. Since internal_links/external_links are arrays, .length correctly derives the count. I don't think this is a bug — happy to switch to the links_count_* fields directly if we'd rather avoid deriving a count from the full URL list, but the current code isn't producing undefined for non-zero values given the actual API contract. Leaving as-is unless you see contrary evidence from a live response.

Comment thread apps/sim/tools/ahrefs/rank_tracker_competitors_stats.ts Outdated
@greptile-apps

greptile-apps Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR audits and extends the Ahrefs integration — fixing three data-correctness bugs and adding 13 new v3 API tools. The changes are self-contained to the Ahrefs tool layer and do not touch shared infrastructure.

  • Bug fixes: broken_backlinks column correction (http_code_targethttp_code), USD-cents-to-dollars conversion for organicCost/paidCost/cpc in keyword_overview, metrics, and metrics_history, and a missing exact option in the top_pages mode dropdown.
  • New tools: 13 new endpoints added (Rank Tracker overview/SERP/competitors, Batch Analysis, Site Audit Page Explorer, history trend endpoints for DR/metrics/refdomains/keywords, Related Terms, Anchors, Paid Pages), each consistently following the existing tool pattern with proper cents-to-USD conversion on all monetary fields.

Confidence Score: 5/5

This PR is safe to merge — all changes are additive or targeted bug fixes within the Ahrefs tool layer, with no shared infrastructure touched.

The three bug fixes (wrong column name, missing cents-to-USD conversion, missing dropdown option) are narrow and correct. All 13 new tools follow the established pattern with consistent monetary conversion and error handling. Prior review rounds caught and resolved the SERP overview cents issue and the batch analysis dual-key fallback — both confirmed fixed in the current HEAD. No logic errors or data-correctness problems remain.

No files require special attention. The rank_tracker_competitors_stats.ts uses an unusual hyphenated JSON key (data['competitors-metrics']) but the author confirmed this against live API docs.

Important Files Changed

Filename Overview
apps/sim/blocks/blocks/ahrefs.ts Large block definition update adding UI inputs and outputs for all 13 new operations plus the exact mode fix for top_pages. Follows established block patterns consistently.
apps/sim/tools/ahrefs/types.ts New file consolidating all Ahrefs type definitions; well-structured with proper TypeScript interfaces for all 20+ tool param/response pairs.
apps/sim/tools/registry.ts Registers all 13 new Ahrefs tools with correct kebab-case keys matching tool id fields. Alphabetical ordering maintained within the ahrefs group.
apps/sim/tools/ahrefs/rank_tracker_serp_overview.ts New SERP overview tool; value field correctly divides by 100 (addressed from a prior review round). Response mapped from data.positions, well-structured output schema.
apps/sim/tools/ahrefs/rank_tracker_competitors_stats.ts New tool; response mapped from data['competitors-metrics'] (hyphenated key per live API docs). trafficValue correctly divided by 100. No issues found.
apps/sim/tools/ahrefs/batch_analysis.ts POST-based batch tool; select sent as an array in the JSON body, response mapped from data.targets only (dual-key fallback removed in a prior round). Clean implementation.
apps/sim/tools/ahrefs/metrics_history.ts New historical traffic/cost tool; SELECT_FIELDS constant is declared and correctly used in the request URL. org_cost and paid_cost properly divided by 100.
apps/sim/tools/ahrefs/rank_tracker_competitors_overview.ts New competitors overview tool; output key renamed to competitorKeywords to avoid collision with ahrefs_organic_keywords. Competitor value field correctly divided by 100.
apps/sim/tools/ahrefs/site_audit_page_explorer.ts New site audit tool; internal_links and external_links correctly treated as arrays (per confirmed API schema) with .length for counts. Clean implementation.
apps/sim/tools/ahrefs/metrics.ts Fixes organicCost and paidCost from raw cents to USD by dividing by 100 using typeof guard — correct and consistent with the pattern used across the new tools.
apps/sim/tools/ahrefs/keyword_overview.ts Single-line fix for cpc dividing by 100 to convert from cents to USD — correct.
apps/sim/tools/ahrefs/top_pages.ts Fixes value field to divide by 100 (cents to USD) and adds exact to the mode dropdown description — correct.
apps/sim/tools/ahrefs/related_terms.ts New related terms tool; cpc correctly divided by 100. Uses keywords URL param (API convention) for a single-keyword input. Clean.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[AhrefsBlock UI] -->|selects operation| B{Operation Type}
    B --> C[Site Explorer Tools]
    B --> D[Keywords Explorer Tools]
    B --> E[Rank Tracker Tools]
    B --> F[Batch Analysis]
    B --> G[Site Audit Tools]
    C --> C1[Domain Rating / History]
    C --> C2[Backlinks / Broken Backlinks / Stats]
    C --> C3[Referring Domains / History]
    C --> C4[Organic Keywords / Competitors]
    C --> C5[Top Pages / Paid Pages]
    C --> C6[Anchors]
    C --> C7[Metrics / Metrics History]
    C --> C8[Keywords History]
    D --> D1[Keyword Overview]
    D --> D2[Related Terms]
    E --> E1[Overview]
    E --> E2[SERP Overview]
    E --> E3[Competitors Overview]
    E --> E4[Competitors Stats]
    F --> F1[Batch Analysis POST]
    G --> G1[Page Explorer]
    C1 & C2 & C3 & C4 & C5 & C6 & C7 & C8 --> H[transformResponse]
    D1 & D2 --> H
    E1 & E2 & E3 & E4 --> H
    F1 --> H
    G1 --> H
    H -->|monetary fields| I[div 100 cents to USD]
    H --> J[Structured output]
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    A[AhrefsBlock UI] -->|selects operation| B{Operation Type}
    B --> C[Site Explorer Tools]
    B --> D[Keywords Explorer Tools]
    B --> E[Rank Tracker Tools]
    B --> F[Batch Analysis]
    B --> G[Site Audit Tools]
    C --> C1[Domain Rating / History]
    C --> C2[Backlinks / Broken Backlinks / Stats]
    C --> C3[Referring Domains / History]
    C --> C4[Organic Keywords / Competitors]
    C --> C5[Top Pages / Paid Pages]
    C --> C6[Anchors]
    C --> C7[Metrics / Metrics History]
    C --> C8[Keywords History]
    D --> D1[Keyword Overview]
    D --> D2[Related Terms]
    E --> E1[Overview]
    E --> E2[SERP Overview]
    E --> E3[Competitors Overview]
    E --> E4[Competitors Stats]
    F --> F1[Batch Analysis POST]
    G --> G1[Page Explorer]
    C1 & C2 & C3 & C4 & C5 & C6 & C7 & C8 --> H[transformResponse]
    D1 & D2 --> H
    E1 & E2 & E3 & E4 --> H
    F1 --> H
    G1 --> H
    H -->|monetary fields| I[div 100 cents to USD]
    H --> J[Structured output]
Loading

Reviews (8): Last reviewed commit: "fix(ahrefs): split shared date subBlock ..." | Re-trigger Greptile

Comment thread apps/sim/tools/ahrefs/site_audit_page_explorer.ts
Comment thread apps/sim/tools/ahrefs/rank_tracker_serp_overview.ts Outdated
Comment thread apps/sim/tools/ahrefs/batch_analysis.ts
…lback key

Rank Tracker SERP Overview's value field, Competitors Stats' trafficValue,
and Competitors Overview's nested competitor value were all left in USD
cents while every other monetary field in the integration converts to USD
- fixed for consistency with the rest of the integration.

Also drops the unverified `data.results` fallback in Batch Analysis; the
Ahrefs v3 docs confirm the response key is always `targets`.
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile review

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cursor review

Comment thread apps/sim/tools/ahrefs/keywords_history.ts
The generated docs page was stale after the previous commit converted
rank_tracker_serp_overview.value, rank_tracker_competitors_stats.trafficValue,
and rank_tracker_competitors_overview's nested value from cents to USD -
regenerating picks up the corrected field descriptions.
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

Fixed the stale docs Greptile flagged (SERP Overview value field description still said "USD cents" after the code was updated to convert to USD) — regenerated docs in 3c3d8bf. Also verified and pushed back (with live-docs schema evidence) on the two site_audit_page_explorer array-vs-count claims and the new keywords_history bucket-column claim — replies posted on those threads.

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile review

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cursor review

…_pages conversion, revert unverified competitor value conversions

Independent re-verification against live Ahrefs v3 docs surfaced two real
regressions from the earlier fix rounds and one missed conversion:

- broken_backlinks: the earlier fix changed the selected column from
  http_code_target to http_code, but the docs say http_code is the
  *referring page's* status and http_code_target is the *broken target
  page's* status - the tool needs the latter (matches its own output
  description). Reverted to http_code_target.
- top_pages: value field was never divided by 100 despite the docs stating
  it's in USD cents and the output already claiming USD - fixed.
- rank_tracker_competitors_stats.trafficValue and the nested competitor.value
  in rank_tracker_competitors_overview were converted from cents to USD last
  round on a "match every other monetary field" assumption, but the live docs
  do not document these two fields as cents (unlike every field that was
  correctly converted). Reverted to passthrough and dropped the "(USD)"
  claim from their descriptions until Ahrefs documents the unit.

Also added the missing "exact" mode option to top_pages' mode param
description, matching every sibling tool.
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

Ran a completely independent, from-scratch re-verification of all 23 tools against live Ahrefs v3 docs (not trusting any prior round's conclusions) and self-caught 3 issues in e4dcffc, none of which the bots had flagged:

  • Regression: an earlier round "fixed" broken_backlinks from http_code_targethttp_code, but that was backwards — docs confirm http_code is the referring page's status and http_code_target is the broken target's status (which is what the tool actually needs). Reverted.
  • Missed conversion: top_pages.value was never divided by 100 despite docs stating it's in USD cents (and the output already claimed USD). Fixed.
  • Unverified conversion reverted: last round's "convert for consistency" changes to rank_tracker_competitors_stats.trafficValue and the nested value in rank_tracker_competitors_overview weren't actually backed by docs text (unlike every other field that says "in USD cents" explicitly) — reverted to passthrough rather than guess.

Docs regenerated to match. Re-requesting review.

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile review

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cursor review

Comment thread apps/sim/tools/ahrefs/rank_tracker_competitors_overview.ts Outdated
Both bots independently flagged these two fields as inconsistent with
every other monetary field in the integration, all 7 of which are
explicitly documented as USD cents. Neither field has explicit unit
documentation (one is undocumented as cents, the other's schema isn't
statically retrievable at all), but given the unanimous pattern across
every other verified field and no contrary evidence, converting for
consistency is the better bet than leaving them as an outlier.
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile review

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cursor review

url.searchParams.set('country', params.country || 'us')
url.searchParams.set('keywords', params.keyword)
if (params.terms) url.searchParams.set('terms', params.terms)
if (params.viewFor) url.searchParams.set('view_for', params.viewFor)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Related terms omits documented defaults

Medium Severity

The new ahrefs_related_terms request only adds terms and view_for when those params are truthy, while param descriptions promise defaults of all and top_10. Omitted values (common on direct agent tool calls) rely on undocumented API defaults instead of the documented behavior, unlike country, which always falls back to us.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit ea0e1a4. Configure here.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Checked the live docs for GET /v3/keywords-explorer/related-terms directly — both params have documented API-side defaults that match our own param descriptions exactly: terms defaults to all, view_for defaults to top_10 (confirmed via the docs' own "Default:" field for each param, not just prose). Omitting them when not provided isn't relying on an undocumented default — it's relying on the exact documented one. Only country needed an explicit client-side fallback because its default isn't spelled out the same way in the docs. Not changing this; happy to revisit if you can point to evidence the live API's actual default diverges from what's documented.

Repo convention disallows non-TSDoc comments; removed the three
explanatory // comments this PR added next to cents-to-USD conversions
(keyword_overview, paid_pages, related_terms) - pre-existing comments
elsewhere in the file are untouched, out of scope for this PR.
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile review

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cursor review

Comment thread apps/sim/tools/ahrefs/paid_pages.ts
Comment thread apps/sim/tools/ahrefs/metrics_history.ts
…ools

paid_pages, metrics_history, keywords_history, and batch_analysis were the
only 4 of the 11 tools with an optional country param that didn't fall back
to "us" when omitted, unlike domain_rating, metrics, keyword_overview,
organic_keywords, organic_competitors, top_pages, and related_terms - all
of which default client-side. Aligned all four to the same convention so
direct tool/agent calls without an explicit country get the same behavior
regardless of which operation is used.
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile review

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cursor review

Comment thread apps/sim/blocks/blocks/ahrefs.ts
…ions

site_audit_page_explorer and rank_tracker_serp_overview both reused the
generic 'date' subBlock id with YYYY-MM-DDThh:mm:ss semantics, while every
other operation using that same id expects YYYY-MM-DD. Switching operations
without clearing the field could carry a stale wrong-format value into the
new operation's request. Split into distinct ids (crawlDate, asOfDate)
mapped back to each tool's date param in tools.config.params.
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile review

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cursor review

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Bugbot reviewed your changes and found no new issues!

2 issues from previous reviews remain unresolved.

Fix All in Cursor

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit b1b5611. Configure here.

@waleedlatif1 waleedlatif1 merged commit 918ba8a into staging Jul 6, 2026
18 checks passed
@waleedlatif1 waleedlatif1 deleted the feat/ahrefs-integration branch July 6, 2026 23:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant