chore: import upstream snapshot with attribution
Publish CLI Package / publish-npm (push) Waiting to run
Publish Python SDK / publish-pypi (push) Waiting to run
Publish TypeScript SDK / publish-npm (push) Waiting to run
CI / Migrate Dev DB (push) Has been skipped
CI / Detect Version (push) Has been cancelled
CI / Migrate DB (push) Has been cancelled
CI / Build Dev ECR (./docker/app.Dockerfile, ECR_APP) (push) Has been cancelled
CI / Build Dev ECR (./docker/db.Dockerfile, ECR_MIGRATIONS) (push) Has been cancelled
CI / Build Dev ECR (./docker/pii.Dockerfile, ECR_PII) (push) Has been cancelled
CI / Build Dev ECR (./docker/realtime.Dockerfile, ECR_REALTIME) (push) Has been cancelled
CI / Deploy Trigger.dev (Dev) (push) Has been cancelled
CI / Build AMD64 (./docker/app.Dockerfile, ECR_APP, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build AMD64 (./docker/db.Dockerfile, ECR_MIGRATIONS, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build AMD64 (./docker/pii.Dockerfile, ECR_PII, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build AMD64 (./docker/realtime.Dockerfile, ECR_REALTIME, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/app.Dockerfile, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/db.Dockerfile, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/pii.Dockerfile, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/realtime.Dockerfile, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Check Docs Changes (push) Has been cancelled
CI / Process Docs (push) Has been cancelled
CI / Create GitHub Release (push) Has been cancelled
CI / Test and Build (push) Has been cancelled

This commit is contained in:
wehub-resource-sync
2026-07-13 13:20:55 +08:00
commit d25d482dc2
13754 changed files with 4996608 additions and 0 deletions
+120
View File
@@ -0,0 +1,120 @@
import type { AhrefsAnchorsParams, AhrefsAnchorsResponse } from '@/tools/ahrefs/types'
import type { ToolConfig } from '@/tools/types'
const SELECT_FIELDS = 'anchor,links_to_target,dofollow_links,refdomains,first_seen,last_seen'
export const anchorsTool: ToolConfig<AhrefsAnchorsParams, AhrefsAnchorsResponse> = {
id: 'ahrefs_anchors',
name: 'Ahrefs Anchors',
description:
"Get the anchor text distribution for a target domain or URL's backlinks, showing how many links and referring domains use each anchor text.",
version: '1.0.0',
params: {
target: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description:
'The target domain or URL to analyze. Example: "example.com" or "https://example.com/page"',
},
mode: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Analysis mode: domain (entire domain), prefix (URL prefix), subdomains (include all subdomains, default), exact (exact URL match)',
},
history: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Historical scope: "live" (currently live), "all_time" (default, includes lost backlinks), or "since:YYYY-MM-DD" (backlinks found since a date)',
},
limit: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Maximum number of results to return. Example: 50 (default: 1000)',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Ahrefs API Key',
},
},
request: {
url: (params) => {
const url = new URL('https://api.ahrefs.com/v3/site-explorer/anchors')
url.searchParams.set('target', params.target)
url.searchParams.set('select', SELECT_FIELDS)
if (params.mode) url.searchParams.set('mode', params.mode)
url.searchParams.set('history', params.history || 'all_time')
if (params.limit) url.searchParams.set('limit', String(params.limit))
return url.toString()
},
method: 'GET',
headers: (params) => ({
Accept: 'application/json',
Authorization: `Bearer ${params.apiKey}`,
}),
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
throw new Error(data.error?.message || data.error || 'Failed to get anchors')
}
const anchors = (data.anchors || []).map((item: any) => ({
anchor: item.anchor || '',
backlinks: item.links_to_target ?? 0,
dofollowBacklinks: item.dofollow_links ?? 0,
referringDomains: item.refdomains ?? 0,
firstSeen: item.first_seen || '',
lastSeen: item.last_seen ?? null,
}))
return {
success: true,
output: {
anchors,
},
}
},
outputs: {
anchors: {
type: 'array',
description: 'Anchor text distribution for the backlink profile',
items: {
type: 'object',
properties: {
anchor: { type: 'string', description: 'The anchor text' },
backlinks: { type: 'number', description: 'Total backlinks using this anchor text' },
dofollowBacklinks: {
type: 'number',
description: 'Number of dofollow backlinks using this anchor text',
},
referringDomains: {
type: 'number',
description: 'Number of unique referring domains using this anchor text',
},
firstSeen: {
type: 'string',
description: 'When a link with this anchor was first found',
},
lastSeen: {
type: 'string',
description: 'When a backlink with this anchor was last seen (null if still live)',
optional: true,
},
},
},
},
},
}
+113
View File
@@ -0,0 +1,113 @@
import type { AhrefsBacklinksParams, AhrefsBacklinksResponse } from '@/tools/ahrefs/types'
import type { ToolConfig } from '@/tools/types'
const SELECT_FIELDS =
'url_from,url_to,anchor,domain_rating_source,is_dofollow,first_seen,last_visited'
export const backlinksTool: ToolConfig<AhrefsBacklinksParams, AhrefsBacklinksResponse> = {
id: 'ahrefs_backlinks',
name: 'Ahrefs Backlinks',
description:
'Get a list of backlinks pointing to a target domain or URL. Returns details about each backlink including source URL, anchor text, and domain rating.',
version: '1.0.0',
params: {
target: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description:
'The target domain or URL to analyze. Example: "example.com" or "https://example.com/page"',
},
mode: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Analysis mode: domain (entire domain), prefix (URL prefix), subdomains (include all subdomains, default), exact (exact URL match). Example: "domain"',
},
history: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Historical scope: "live" (currently live backlinks), "all_time" (default, includes lost backlinks), or "since:YYYY-MM-DD" (backlinks found since a date).',
},
limit: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Maximum number of results to return. Example: 50 (default: 1000)',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Ahrefs API Key',
},
},
request: {
url: (params) => {
const url = new URL('https://api.ahrefs.com/v3/site-explorer/all-backlinks')
url.searchParams.set('target', params.target)
url.searchParams.set('select', SELECT_FIELDS)
if (params.mode) url.searchParams.set('mode', params.mode)
url.searchParams.set('history', params.history || 'all_time')
if (params.limit) url.searchParams.set('limit', String(params.limit))
return url.toString()
},
method: 'GET',
headers: (params) => ({
Accept: 'application/json',
Authorization: `Bearer ${params.apiKey}`,
}),
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
throw new Error(data.error?.message || data.error || 'Failed to get backlinks')
}
const backlinks = (data.backlinks || []).map((link: any) => ({
urlFrom: link.url_from || '',
urlTo: link.url_to || '',
anchor: link.anchor || '',
domainRatingSource: link.domain_rating_source ?? 0,
isDofollow: link.is_dofollow ?? false,
firstSeen: link.first_seen || '',
lastVisited: link.last_visited || '',
}))
return {
success: true,
output: {
backlinks,
},
}
},
outputs: {
backlinks: {
type: 'array',
description: 'List of backlinks pointing to the target',
items: {
type: 'object',
properties: {
urlFrom: { type: 'string', description: 'The URL of the page containing the backlink' },
urlTo: { type: 'string', description: 'The URL being linked to' },
anchor: { type: 'string', description: 'The anchor text of the link' },
domainRatingSource: {
type: 'number',
description: 'Domain Rating of the linking domain',
},
isDofollow: { type: 'boolean', description: 'Whether the link is dofollow' },
firstSeen: { type: 'string', description: 'When the backlink was first discovered' },
lastVisited: { type: 'string', description: 'When the backlink was last checked' },
},
},
},
},
}
+103
View File
@@ -0,0 +1,103 @@
import type { AhrefsBacklinksStatsParams, AhrefsBacklinksStatsResponse } from '@/tools/ahrefs/types'
import type { ToolConfig } from '@/tools/types'
export const backlinksStatsTool: ToolConfig<
AhrefsBacklinksStatsParams,
AhrefsBacklinksStatsResponse
> = {
id: 'ahrefs_backlinks_stats',
name: 'Ahrefs Backlinks Stats',
description:
'Get backlink and referring domain totals for a target domain or URL, both currently live and across all time.',
version: '1.0.0',
params: {
target: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description:
'The target domain or URL to analyze. Example: "example.com" or "https://example.com/page"',
},
mode: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Analysis mode: domain (entire domain), prefix (URL prefix), subdomains (include all subdomains, default), exact (exact URL match). Example: "domain"',
},
date: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Date to report metrics on, in YYYY-MM-DD format (defaults to today)',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Ahrefs API Key',
},
},
request: {
url: (params) => {
const url = new URL('https://api.ahrefs.com/v3/site-explorer/backlinks-stats')
url.searchParams.set('target', params.target)
// Date is required - default to today if not provided
const date = params.date || new Date().toISOString().split('T')[0]
url.searchParams.set('date', date)
if (params.mode) url.searchParams.set('mode', params.mode)
return url.toString()
},
method: 'GET',
headers: (params) => ({
Accept: 'application/json',
Authorization: `Bearer ${params.apiKey}`,
}),
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
throw new Error(data.error?.message || data.error || 'Failed to get backlinks stats')
}
const metrics = data.metrics || {}
return {
success: true,
output: {
stats: {
liveBacklinks: metrics.live ?? 0,
liveReferringDomains: metrics.live_refdomains ?? 0,
allTimeBacklinks: metrics.all_time ?? 0,
allTimeReferringDomains: metrics.all_time_refdomains ?? 0,
},
},
}
},
outputs: {
stats: {
type: 'object',
description: 'Backlink and referring domain totals',
properties: {
liveBacklinks: { type: 'number', description: 'Number of currently live backlinks' },
liveReferringDomains: {
type: 'number',
description: 'Number of currently live referring domains',
},
allTimeBacklinks: {
type: 'number',
description: 'Total backlinks ever discovered, including lost ones',
},
allTimeReferringDomains: {
type: 'number',
description: 'Total referring domains ever discovered, including lost ones',
},
},
},
},
}
+165
View File
@@ -0,0 +1,165 @@
import type { AhrefsBatchAnalysisParams, AhrefsBatchAnalysisResponse } from '@/tools/ahrefs/types'
import type { ToolConfig } from '@/tools/types'
const SELECT_FIELDS =
'url,domain_rating,ahrefs_rank,backlinks,refdomains,org_traffic,org_keywords,paid_traffic'
export const batchAnalysisTool: ToolConfig<AhrefsBatchAnalysisParams, AhrefsBatchAnalysisResponse> =
{
id: 'ahrefs_batch_analysis',
name: 'Ahrefs Batch Analysis',
description:
'Get bulk SEO metrics (Domain Rating, backlinks, referring domains, organic traffic, and more) for multiple domains or URLs in a single request. Useful for comparing many competitors at once.',
version: '1.0.0',
params: {
targets: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description:
'Comma-separated list of domains or URLs to analyze. Example: "example.com,competitor.com"',
},
mode: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Analysis mode applied to every target: domain (entire domain), prefix (URL prefix), subdomains (include all subdomains, default), exact (exact URL match)',
},
protocol: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Protocol applied to every target: "both" (default), "http", or "https"',
},
country: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Country code for traffic data. Example: "us", "gb", "de" (default: "us")',
},
volumeMode: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Search volume calculation: "monthly" or "average" (default: "monthly")',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Ahrefs API Key',
},
},
request: {
url: () => 'https://api.ahrefs.com/v3/batch-analysis/batch-analysis',
method: 'POST',
headers: (params) => ({
Accept: 'application/json',
'Content-Type': 'application/json',
Authorization: `Bearer ${params.apiKey}`,
}),
body: (params) => {
const targets = params.targets
.split(',')
.map((target) => target.trim())
.filter((target) => target.length > 0)
.map((url) => ({
url,
mode: params.mode || 'subdomains',
protocol: params.protocol || 'both',
}))
return {
select: SELECT_FIELDS.split(','),
targets,
country: params.country || 'us',
volume_mode: params.volumeMode || 'monthly',
}
},
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
throw new Error(data.error?.message || data.error || 'Failed to run batch analysis')
}
const results = (data.targets || []).map((item: any) => ({
url: item.url || '',
index: item.index ?? 0,
domainRating: item.domain_rating ?? null,
ahrefsRank: item.ahrefs_rank ?? null,
backlinks: item.backlinks ?? null,
referringDomains: item.refdomains ?? null,
organicTraffic: item.org_traffic ?? null,
organicKeywords: item.org_keywords ?? null,
paidTraffic: item.paid_traffic ?? null,
error: item.error ?? null,
}))
return {
success: true,
output: {
results,
},
}
},
outputs: {
results: {
type: 'array',
description: 'Bulk metrics for each analyzed target, in submission order',
items: {
type: 'object',
properties: {
url: { type: 'string', description: 'The analyzed target URL or domain' },
index: { type: 'number', description: 'Index of the target in the submitted list' },
domainRating: {
type: 'number',
description: 'Domain Rating score (0-100)',
optional: true,
},
ahrefsRank: {
type: 'number',
description: 'Ahrefs Rank (global ranking)',
optional: true,
},
backlinks: {
type: 'number',
description: 'Total backlinks to the target',
optional: true,
},
referringDomains: {
type: 'number',
description: 'Unique domains linking to the target',
optional: true,
},
organicTraffic: {
type: 'number',
description: 'Estimated monthly organic traffic',
optional: true,
},
organicKeywords: {
type: 'number',
description: 'Number of organic keywords ranked (top 100)',
optional: true,
},
paidTraffic: {
type: 'number',
description: 'Estimated monthly paid search traffic',
optional: true,
},
error: {
type: 'string',
description: 'Error message if this target could not be analyzed',
optional: true,
},
},
},
},
},
}
+113
View File
@@ -0,0 +1,113 @@
import type {
AhrefsBrokenBacklinksParams,
AhrefsBrokenBacklinksResponse,
} from '@/tools/ahrefs/types'
import type { ToolConfig } from '@/tools/types'
const SELECT_FIELDS = 'url_from,url_to,http_code_target,anchor,domain_rating_source'
export const brokenBacklinksTool: ToolConfig<
AhrefsBrokenBacklinksParams,
AhrefsBrokenBacklinksResponse
> = {
id: 'ahrefs_broken_backlinks',
name: 'Ahrefs Broken Backlinks',
description:
'Get a list of broken backlinks pointing to a target domain or URL. Useful for identifying link reclamation opportunities.',
version: '1.0.0',
params: {
target: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description:
'The target domain or URL to analyze. Example: "example.com" or "https://example.com/page"',
},
mode: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Analysis mode: domain (entire domain), prefix (URL prefix), subdomains (include all subdomains, default), exact (exact URL match). Example: "domain"',
},
limit: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Maximum number of results to return. Example: 50 (default: 1000)',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Ahrefs API Key',
},
},
request: {
url: (params) => {
const url = new URL('https://api.ahrefs.com/v3/site-explorer/broken-backlinks')
url.searchParams.set('target', params.target)
url.searchParams.set('select', SELECT_FIELDS)
if (params.mode) url.searchParams.set('mode', params.mode)
if (params.limit) url.searchParams.set('limit', String(params.limit))
return url.toString()
},
method: 'GET',
headers: (params) => ({
Accept: 'application/json',
Authorization: `Bearer ${params.apiKey}`,
}),
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
throw new Error(data.error?.message || data.error || 'Failed to get broken backlinks')
}
const brokenBacklinks = (data.backlinks || []).map((link: any) => ({
urlFrom: link.url_from || '',
urlTo: link.url_to || '',
httpCode: link.http_code_target ?? null,
anchor: link.anchor || '',
domainRatingSource: link.domain_rating_source ?? 0,
}))
return {
success: true,
output: {
brokenBacklinks,
},
}
},
outputs: {
brokenBacklinks: {
type: 'array',
description: 'List of broken backlinks',
items: {
type: 'object',
properties: {
urlFrom: {
type: 'string',
description: 'The URL of the page containing the broken link',
},
urlTo: { type: 'string', description: 'The broken URL being linked to' },
httpCode: {
type: 'number',
description: 'HTTP status code of the broken target URL (e.g., 404, 410)',
optional: true,
},
anchor: { type: 'string', description: 'The anchor text of the link' },
domainRatingSource: {
type: 'number',
description: 'Domain Rating of the linking domain',
},
},
},
},
},
}
+75
View File
@@ -0,0 +1,75 @@
import type { AhrefsDomainRatingParams, AhrefsDomainRatingResponse } from '@/tools/ahrefs/types'
import type { ToolConfig } from '@/tools/types'
export const domainRatingTool: ToolConfig<AhrefsDomainRatingParams, AhrefsDomainRatingResponse> = {
id: 'ahrefs_domain_rating',
name: 'Ahrefs Domain Rating',
description:
"Get the Domain Rating (DR) and Ahrefs Rank for a target domain. Domain Rating shows the strength of a website's backlink profile on a scale from 0 to 100.",
version: '1.0.0',
params: {
target: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The target domain to analyze (e.g., example.com)',
},
date: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Date for historical data in YYYY-MM-DD format (defaults to today)',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Ahrefs API Key',
},
},
request: {
url: (params) => {
const url = new URL('https://api.ahrefs.com/v3/site-explorer/domain-rating')
url.searchParams.set('target', params.target)
// Date is required - default to today if not provided
const date = params.date || new Date().toISOString().split('T')[0]
url.searchParams.set('date', date)
return url.toString()
},
method: 'GET',
headers: (params) => ({
Accept: 'application/json',
Authorization: `Bearer ${params.apiKey}`,
}),
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
throw new Error(data.error?.message || data.error || 'Failed to get domain rating')
}
return {
success: true,
output: {
domainRating: data.domain_rating?.domain_rating ?? 0,
ahrefsRank: data.domain_rating?.ahrefs_rank ?? null,
},
}
},
outputs: {
domainRating: {
type: 'number',
description: 'Domain Rating score (0-100)',
},
ahrefsRank: {
type: 'number',
description: 'Ahrefs Rank - global ranking based on backlink profile strength',
optional: true,
},
},
}
@@ -0,0 +1,100 @@
import type {
AhrefsDomainRatingHistoryParams,
AhrefsDomainRatingHistoryResponse,
} from '@/tools/ahrefs/types'
import type { ToolConfig } from '@/tools/types'
export const domainRatingHistoryTool: ToolConfig<
AhrefsDomainRatingHistoryParams,
AhrefsDomainRatingHistoryResponse
> = {
id: 'ahrefs_domain_rating_history',
name: 'Ahrefs Domain Rating History',
description:
'Get the historical Domain Rating (DR) trend for a target domain or URL over a date range, grouped daily, weekly, or monthly.',
version: '1.0.0',
params: {
target: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The target domain or URL to analyze. Example: "example.com"',
},
dateFrom: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Start date of the historical period, in YYYY-MM-DD format',
},
dateTo: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'End date of the historical period, in YYYY-MM-DD format (defaults to today)',
},
historyGrouping: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Time interval for grouping data points: "daily", "weekly", or "monthly" (default: "monthly")',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Ahrefs API Key',
},
},
request: {
url: (params) => {
const url = new URL('https://api.ahrefs.com/v3/site-explorer/domain-rating-history')
url.searchParams.set('target', params.target)
url.searchParams.set('date_from', params.dateFrom)
if (params.dateTo) url.searchParams.set('date_to', params.dateTo)
if (params.historyGrouping) url.searchParams.set('history_grouping', params.historyGrouping)
return url.toString()
},
method: 'GET',
headers: (params) => ({
Accept: 'application/json',
Authorization: `Bearer ${params.apiKey}`,
}),
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
throw new Error(data.error?.message || data.error || 'Failed to get domain rating history')
}
const domainRatings = (data.domain_ratings || []).map((item: any) => ({
date: item.date || '',
domainRating: item.domain_rating ?? 0,
}))
return {
success: true,
output: {
domainRatings,
},
}
},
outputs: {
domainRatings: {
type: 'array',
description: 'Historical Domain Rating data points',
items: {
type: 'object',
properties: {
date: { type: 'string', description: 'The date of the measurement' },
domainRating: { type: 'number', description: 'Domain Rating score (0-100) on this date' },
},
},
},
},
}
+49
View File
@@ -0,0 +1,49 @@
import { anchorsTool } from '@/tools/ahrefs/anchors'
import { backlinksTool } from '@/tools/ahrefs/backlinks'
import { backlinksStatsTool } from '@/tools/ahrefs/backlinks_stats'
import { batchAnalysisTool } from '@/tools/ahrefs/batch_analysis'
import { brokenBacklinksTool } from '@/tools/ahrefs/broken_backlinks'
import { domainRatingTool } from '@/tools/ahrefs/domain_rating'
import { domainRatingHistoryTool } from '@/tools/ahrefs/domain_rating_history'
import { keywordOverviewTool } from '@/tools/ahrefs/keyword_overview'
import { keywordsHistoryTool } from '@/tools/ahrefs/keywords_history'
import { metricsTool } from '@/tools/ahrefs/metrics'
import { metricsHistoryTool } from '@/tools/ahrefs/metrics_history'
import { organicCompetitorsTool } from '@/tools/ahrefs/organic_competitors'
import { organicKeywordsTool } from '@/tools/ahrefs/organic_keywords'
import { paidPagesTool } from '@/tools/ahrefs/paid_pages'
import { rankTrackerCompetitorsOverviewTool } from '@/tools/ahrefs/rank_tracker_competitors_overview'
import { rankTrackerCompetitorsStatsTool } from '@/tools/ahrefs/rank_tracker_competitors_stats'
import { rankTrackerOverviewTool } from '@/tools/ahrefs/rank_tracker_overview'
import { rankTrackerSerpOverviewTool } from '@/tools/ahrefs/rank_tracker_serp_overview'
import { refdomainsHistoryTool } from '@/tools/ahrefs/refdomains_history'
import { referringDomainsTool } from '@/tools/ahrefs/referring_domains'
import { relatedTermsTool } from '@/tools/ahrefs/related_terms'
import { siteAuditPageExplorerTool } from '@/tools/ahrefs/site_audit_page_explorer'
import { topPagesTool } from '@/tools/ahrefs/top_pages'
export const ahrefsDomainRatingTool = domainRatingTool
export const ahrefsBacklinksTool = backlinksTool
export const ahrefsBacklinksStatsTool = backlinksStatsTool
export const ahrefsReferringDomainsTool = referringDomainsTool
export const ahrefsOrganicKeywordsTool = organicKeywordsTool
export const ahrefsTopPagesTool = topPagesTool
export const ahrefsKeywordOverviewTool = keywordOverviewTool
export const ahrefsBrokenBacklinksTool = brokenBacklinksTool
export const ahrefsMetricsTool = metricsTool
export const ahrefsOrganicCompetitorsTool = organicCompetitorsTool
export const ahrefsRankTrackerOverviewTool = rankTrackerOverviewTool
export const ahrefsRankTrackerSerpOverviewTool = rankTrackerSerpOverviewTool
export const ahrefsRankTrackerCompetitorsOverviewTool = rankTrackerCompetitorsOverviewTool
export const ahrefsRankTrackerCompetitorsStatsTool = rankTrackerCompetitorsStatsTool
export const ahrefsBatchAnalysisTool = batchAnalysisTool
export const ahrefsSiteAuditPageExplorerTool = siteAuditPageExplorerTool
export const ahrefsDomainRatingHistoryTool = domainRatingHistoryTool
export const ahrefsMetricsHistoryTool = metricsHistoryTool
export const ahrefsRefdomainsHistoryTool = refdomainsHistoryTool
export const ahrefsKeywordsHistoryTool = keywordsHistoryTool
export const ahrefsRelatedTermsTool = relatedTermsTool
export const ahrefsAnchorsTool = anchorsTool
export const ahrefsPaidPagesTool = paidPagesTool
export * from '@/tools/ahrefs/types'
+129
View File
@@ -0,0 +1,129 @@
import type {
AhrefsKeywordOverviewParams,
AhrefsKeywordOverviewResponse,
} from '@/tools/ahrefs/types'
import type { ToolConfig } from '@/tools/types'
const SELECT_FIELDS =
'keyword,volume,difficulty,cpc,clicks,searches_pct_clicks_organic_only,parent_topic,traffic_potential,intents'
export const keywordOverviewTool: ToolConfig<
AhrefsKeywordOverviewParams,
AhrefsKeywordOverviewResponse
> = {
id: 'ahrefs_keyword_overview',
name: 'Ahrefs Keyword Overview',
description:
'Get detailed metrics for a keyword including search volume, keyword difficulty, CPC, clicks, and traffic potential.',
version: '1.0.0',
params: {
keyword: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The keyword to analyze',
},
country: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Country code for keyword data. Example: "us", "gb", "de" (default: "us")',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Ahrefs API Key',
},
},
request: {
url: (params) => {
const url = new URL('https://api.ahrefs.com/v3/keywords-explorer/overview')
url.searchParams.set('keywords', params.keyword)
url.searchParams.set('country', params.country || 'us')
url.searchParams.set('select', SELECT_FIELDS)
return url.toString()
},
method: 'GET',
headers: (params) => ({
Accept: 'application/json',
Authorization: `Bearer ${params.apiKey}`,
}),
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
throw new Error(data.error?.message || data.error || 'Failed to get keyword overview')
}
const result = (data.keywords || [])[0] || {}
return {
success: true,
output: {
overview: {
keyword: result.keyword || '',
searchVolume: result.volume ?? 0,
keywordDifficulty: result.difficulty ?? null,
cpc: typeof result.cpc === 'number' ? result.cpc / 100 : null,
clicks: result.clicks ?? null,
clicksPercentage: result.searches_pct_clicks_organic_only ?? null,
parentTopic: result.parent_topic ?? null,
trafficPotential: result.traffic_potential ?? null,
intents: result.intents ?? null,
},
},
}
},
outputs: {
overview: {
type: 'object',
description: 'Keyword metrics overview',
properties: {
keyword: { type: 'string', description: 'The analyzed keyword' },
searchVolume: { type: 'number', description: 'Monthly search volume' },
keywordDifficulty: {
type: 'number',
description: 'Keyword difficulty score (0-100)',
optional: true,
},
cpc: { type: 'number', description: 'Cost per click in USD', optional: true },
clicks: { type: 'number', description: 'Estimated clicks per month', optional: true },
clicksPercentage: {
type: 'number',
description: 'Percentage of searches that result in an organic click',
optional: true,
},
parentTopic: {
type: 'string',
description: 'The parent topic for this keyword',
optional: true,
},
trafficPotential: {
type: 'number',
description: 'Estimated traffic potential if ranking #1',
optional: true,
},
intents: {
type: 'object',
description:
'Search intent flags (informational, navigational, commercial, transactional, branded, local)',
optional: true,
properties: {
informational: { type: 'boolean', description: 'Query seeks information' },
navigational: { type: 'boolean', description: 'Query seeks a specific site or page' },
commercial: { type: 'boolean', description: 'Query researches a purchase decision' },
transactional: { type: 'boolean', description: 'Query intends to complete a purchase' },
branded: { type: 'boolean', description: 'Query references a specific brand' },
local: { type: 'boolean', description: 'Query seeks local results' },
},
},
},
},
},
}
+126
View File
@@ -0,0 +1,126 @@
import type {
AhrefsKeywordsHistoryParams,
AhrefsKeywordsHistoryResponse,
} from '@/tools/ahrefs/types'
import type { ToolConfig } from '@/tools/types'
const SELECT_FIELDS = 'date,top3,top4_10,top11_20,top21_50,top51_plus'
export const keywordsHistoryTool: ToolConfig<
AhrefsKeywordsHistoryParams,
AhrefsKeywordsHistoryResponse
> = {
id: 'ahrefs_keywords_history',
name: 'Ahrefs Keywords History',
description:
'Get the historical organic keyword ranking distribution for a target domain or URL over a date range: how many keywords rank in each position bucket at each point in time.',
version: '1.0.0',
params: {
target: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The target domain or URL to analyze. Example: "example.com"',
},
dateFrom: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Start date of the historical period, in YYYY-MM-DD format',
},
dateTo: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'End date of the historical period, in YYYY-MM-DD format (defaults to today)',
},
historyGrouping: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Time interval for grouping data points: "daily", "weekly", or "monthly" (default: "monthly")',
},
country: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Country code for search results. Example: "us", "gb", "de" (default: "us")',
},
mode: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Analysis mode: domain (entire domain), prefix (URL prefix), subdomains (include all subdomains, default), exact (exact URL match)',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Ahrefs API Key',
},
},
request: {
url: (params) => {
const url = new URL('https://api.ahrefs.com/v3/site-explorer/keywords-history')
url.searchParams.set('target', params.target)
url.searchParams.set('date_from', params.dateFrom)
url.searchParams.set('select', SELECT_FIELDS)
if (params.historyGrouping) url.searchParams.set('history_grouping', params.historyGrouping)
if (params.dateTo) url.searchParams.set('date_to', params.dateTo)
url.searchParams.set('country', params.country || 'us')
if (params.mode) url.searchParams.set('mode', params.mode)
return url.toString()
},
method: 'GET',
headers: (params) => ({
Accept: 'application/json',
Authorization: `Bearer ${params.apiKey}`,
}),
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
throw new Error(data.error?.message || data.error || 'Failed to get keywords history')
}
const keywordsHistory = (data.keywords || []).map((item: any) => ({
date: item.date || '',
top3: item.top3 ?? 0,
top4To10: item.top4_10 ?? 0,
top11To20: item.top11_20 ?? 0,
top21To50: item.top21_50 ?? 0,
top51Plus: item.top51_plus ?? 0,
}))
return {
success: true,
output: {
keywordsHistory,
},
}
},
outputs: {
keywordsHistory: {
type: 'array',
description: 'Historical organic keyword ranking distribution',
items: {
type: 'object',
properties: {
date: { type: 'string', description: 'Date of the record' },
top3: { type: 'number', description: 'Keywords ranking in top 3 organic results' },
top4To10: { type: 'number', description: 'Keywords ranking in positions 4-10' },
top11To20: { type: 'number', description: 'Keywords ranking in positions 11-20' },
top21To50: { type: 'number', description: 'Keywords ranking in positions 21-50' },
top51Plus: { type: 'number', description: 'Keywords ranking in position 51 and beyond' },
},
},
},
},
}
+116
View File
@@ -0,0 +1,116 @@
import type { AhrefsMetricsParams, AhrefsMetricsResponse } from '@/tools/ahrefs/types'
import type { ToolConfig } from '@/tools/types'
export const metricsTool: ToolConfig<AhrefsMetricsParams, AhrefsMetricsResponse> = {
id: 'ahrefs_metrics',
name: 'Ahrefs Metrics',
description:
'Get a one-call organic and paid search overview for a target domain or URL: organic traffic, organic keywords, paid traffic, paid keywords, and estimated traffic cost.',
version: '1.0.0',
params: {
target: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The target domain or URL to analyze. Example: "example.com"',
},
country: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Country code for traffic data. Example: "us", "gb", "de"',
},
mode: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Analysis mode: domain (entire domain), prefix (URL prefix), subdomains (include all subdomains, default), exact (exact URL match). Example: "domain"',
},
date: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Date to report metrics on, in YYYY-MM-DD format (defaults to today)',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Ahrefs API Key',
},
},
request: {
url: (params) => {
const url = new URL('https://api.ahrefs.com/v3/site-explorer/metrics')
url.searchParams.set('target', params.target)
// Date is required - default to today if not provided
const date = params.date || new Date().toISOString().split('T')[0]
url.searchParams.set('date', date)
url.searchParams.set('country', params.country || 'us')
if (params.mode) url.searchParams.set('mode', params.mode)
return url.toString()
},
method: 'GET',
headers: (params) => ({
Accept: 'application/json',
Authorization: `Bearer ${params.apiKey}`,
}),
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
throw new Error(data.error?.message || data.error || 'Failed to get metrics')
}
const metrics = data.metrics || {}
return {
success: true,
output: {
metrics: {
organicTraffic: metrics.org_traffic ?? 0,
organicKeywords: metrics.org_keywords ?? 0,
organicKeywordsTop3: metrics.org_keywords_1_3 ?? 0,
organicCost: typeof metrics.org_cost === 'number' ? metrics.org_cost / 100 : null,
paidTraffic: metrics.paid_traffic ?? 0,
paidKeywords: metrics.paid_keywords ?? 0,
paidPages: metrics.paid_pages ?? 0,
paidCost: typeof metrics.paid_cost === 'number' ? metrics.paid_cost / 100 : null,
},
},
}
},
outputs: {
metrics: {
type: 'object',
description: 'Organic and paid search overview',
properties: {
organicTraffic: { type: 'number', description: 'Estimated monthly organic traffic' },
organicKeywords: { type: 'number', description: 'Number of organic keywords ranked' },
organicKeywordsTop3: {
type: 'number',
description: 'Number of organic keywords ranking in positions 1-3',
},
organicCost: {
type: 'number',
description: 'Estimated monthly cost to replicate organic traffic via ads (USD)',
optional: true,
},
paidTraffic: { type: 'number', description: 'Estimated monthly paid search traffic' },
paidKeywords: { type: 'number', description: 'Number of paid keywords targeted' },
paidPages: { type: 'number', description: 'Number of pages receiving paid traffic' },
paidCost: {
type: 'number',
description: 'Estimated monthly paid search spend (USD)',
optional: true,
},
},
},
},
}
+136
View File
@@ -0,0 +1,136 @@
import type { AhrefsMetricsHistoryParams, AhrefsMetricsHistoryResponse } from '@/tools/ahrefs/types'
import type { ToolConfig } from '@/tools/types'
const SELECT_FIELDS = 'date,org_traffic,org_cost,paid_traffic,paid_cost'
export const metricsHistoryTool: ToolConfig<
AhrefsMetricsHistoryParams,
AhrefsMetricsHistoryResponse
> = {
id: 'ahrefs_metrics_history',
name: 'Ahrefs Metrics History',
description:
'Get the historical organic and paid traffic trend for a target domain or URL over a date range: organic traffic/cost and paid traffic/cost at each point in time.',
version: '1.0.0',
params: {
target: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The target domain or URL to analyze. Example: "example.com"',
},
dateFrom: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Start date of the historical period, in YYYY-MM-DD format',
},
dateTo: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'End date of the historical period, in YYYY-MM-DD format (defaults to today)',
},
volumeMode: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Search volume calculation: "monthly" or "average" (default: "monthly")',
},
historyGrouping: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Time interval for grouping data points: "daily", "weekly", or "monthly" (default: "monthly")',
},
country: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Country code for traffic data. Example: "us", "gb", "de" (default: "us")',
},
mode: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Analysis mode: domain (entire domain), prefix (URL prefix), subdomains (include all subdomains, default), exact (exact URL match)',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Ahrefs API Key',
},
},
request: {
url: (params) => {
const url = new URL('https://api.ahrefs.com/v3/site-explorer/metrics-history')
url.searchParams.set('target', params.target)
url.searchParams.set('date_from', params.dateFrom)
if (params.dateTo) url.searchParams.set('date_to', params.dateTo)
url.searchParams.set('select', SELECT_FIELDS)
url.searchParams.set('volume_mode', params.volumeMode || 'monthly')
if (params.historyGrouping) url.searchParams.set('history_grouping', params.historyGrouping)
url.searchParams.set('country', params.country || 'us')
if (params.mode) url.searchParams.set('mode', params.mode)
return url.toString()
},
method: 'GET',
headers: (params) => ({
Accept: 'application/json',
Authorization: `Bearer ${params.apiKey}`,
}),
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
throw new Error(data.error?.message || data.error || 'Failed to get metrics history')
}
const metrics = (data.metrics || []).map((item: any) => ({
date: item.date || '',
organicTraffic: item.org_traffic ?? 0,
organicCost: typeof item.org_cost === 'number' ? item.org_cost / 100 : null,
paidTraffic: item.paid_traffic ?? 0,
paidCost: typeof item.paid_cost === 'number' ? item.paid_cost / 100 : null,
}))
return {
success: true,
output: {
metricsHistory: metrics,
},
}
},
outputs: {
metricsHistory: {
type: 'array',
description: 'Historical organic and paid traffic data points',
items: {
type: 'object',
properties: {
date: { type: 'string', description: 'Date of the metric entry' },
organicTraffic: { type: 'number', description: 'Estimated monthly organic visits' },
organicCost: {
type: 'number',
description: 'Estimated monthly cost to replicate organic traffic via ads (USD)',
optional: true,
},
paidTraffic: { type: 'number', description: 'Estimated monthly paid search visits' },
paidCost: {
type: 'number',
description: 'Estimated monthly paid search spend (USD)',
optional: true,
},
},
},
},
},
}
@@ -0,0 +1,138 @@
import type {
AhrefsOrganicCompetitorsParams,
AhrefsOrganicCompetitorsResponse,
} from '@/tools/ahrefs/types'
import type { ToolConfig } from '@/tools/types'
const SELECT_FIELDS =
'competitor_domain,domain_rating,keywords_common,keywords_target,keywords_competitor,traffic'
export const organicCompetitorsTool: ToolConfig<
AhrefsOrganicCompetitorsParams,
AhrefsOrganicCompetitorsResponse
> = {
id: 'ahrefs_organic_competitors',
name: 'Ahrefs Organic Competitors',
description:
'Get domains that compete with a target domain or URL for the same organic keywords, ranked by keyword overlap.',
version: '1.0.0',
params: {
target: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The target domain or URL to analyze. Example: "example.com"',
},
country: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Country code for search results. Example: "us", "gb", "de" (default: "us")',
},
mode: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Analysis mode: domain (entire domain), prefix (URL prefix), subdomains (include all subdomains, default), exact (exact URL match). Example: "domain"',
},
date: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Date to report metrics on, in YYYY-MM-DD format (defaults to today)',
},
limit: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Maximum number of results to return. Example: 50 (default: 1000)',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Ahrefs API Key',
},
},
request: {
url: (params) => {
const url = new URL('https://api.ahrefs.com/v3/site-explorer/organic-competitors')
url.searchParams.set('target', params.target)
url.searchParams.set('country', params.country || 'us')
url.searchParams.set('select', SELECT_FIELDS)
// Date is required - default to today if not provided
const date = params.date || new Date().toISOString().split('T')[0]
url.searchParams.set('date', date)
if (params.mode) url.searchParams.set('mode', params.mode)
if (params.limit) url.searchParams.set('limit', String(params.limit))
return url.toString()
},
method: 'GET',
headers: (params) => ({
Accept: 'application/json',
Authorization: `Bearer ${params.apiKey}`,
}),
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
throw new Error(data.error?.message || data.error || 'Failed to get organic competitors')
}
const competitors = (data.competitors || []).map((competitor: any) => ({
domain: competitor.competitor_domain ?? null,
domainRating: competitor.domain_rating ?? 0,
commonKeywords: competitor.keywords_common ?? 0,
targetKeywords: competitor.keywords_target ?? 0,
competitorKeywords: competitor.keywords_competitor ?? 0,
traffic: competitor.traffic ?? null,
}))
return {
success: true,
output: {
competitors,
},
}
},
outputs: {
competitors: {
type: 'array',
description: 'List of organic search competitors ranked by keyword overlap',
items: {
type: 'object',
properties: {
domain: {
type: 'string',
description: 'The competitor domain',
optional: true,
},
domainRating: { type: 'number', description: 'Domain Rating of the competitor' },
commonKeywords: {
type: 'number',
description: 'Number of keywords the competitor and target both rank for',
},
targetKeywords: {
type: 'number',
description: 'Number of keywords the target ranks for',
},
competitorKeywords: {
type: 'number',
description: 'Number of keywords the competitor ranks for',
},
traffic: {
type: 'number',
description: 'Estimated monthly organic traffic for the competitor',
optional: true,
},
},
},
},
},
}
+134
View File
@@ -0,0 +1,134 @@
import type {
AhrefsOrganicKeywordsParams,
AhrefsOrganicKeywordsResponse,
} from '@/tools/ahrefs/types'
import type { ToolConfig } from '@/tools/types'
const SELECT_FIELDS =
'keyword,volume,best_position,best_position_url,sum_traffic,keyword_difficulty'
export const organicKeywordsTool: ToolConfig<
AhrefsOrganicKeywordsParams,
AhrefsOrganicKeywordsResponse
> = {
id: 'ahrefs_organic_keywords',
name: 'Ahrefs Organic Keywords',
description:
'Get organic keywords that a target domain or URL ranks for in Google search results. Returns keyword details including search volume, ranking position, and estimated traffic.',
version: '1.0.0',
params: {
target: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description:
'The target domain or URL to analyze. Example: "example.com" or "https://example.com/page"',
},
country: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Country code for search results. Example: "us", "gb", "de" (default: "us")',
},
mode: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Analysis mode: domain (entire domain), prefix (URL prefix), subdomains (include all subdomains, default), exact (exact URL match). Example: "domain"',
},
date: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Date to report metrics on, in YYYY-MM-DD format (defaults to today)',
},
limit: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Maximum number of results to return. Example: 50 (default: 1000)',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Ahrefs API Key',
},
},
request: {
url: (params) => {
const url = new URL('https://api.ahrefs.com/v3/site-explorer/organic-keywords')
url.searchParams.set('target', params.target)
url.searchParams.set('country', params.country || 'us')
url.searchParams.set('select', SELECT_FIELDS)
// Date is required - default to today if not provided
const date = params.date || new Date().toISOString().split('T')[0]
url.searchParams.set('date', date)
if (params.mode) url.searchParams.set('mode', params.mode)
if (params.limit) url.searchParams.set('limit', String(params.limit))
return url.toString()
},
method: 'GET',
headers: (params) => ({
Accept: 'application/json',
Authorization: `Bearer ${params.apiKey}`,
}),
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
throw new Error(data.error?.message || data.error || 'Failed to get organic keywords')
}
const keywords = (data.keywords || []).map((kw: any) => ({
keyword: kw.keyword || '',
volume: kw.volume ?? 0,
position: kw.best_position ?? null,
url: kw.best_position_url ?? null,
traffic: kw.sum_traffic ?? 0,
keywordDifficulty: kw.keyword_difficulty ?? null,
}))
return {
success: true,
output: {
keywords,
},
}
},
outputs: {
keywords: {
type: 'array',
description: 'List of organic keywords the target ranks for',
items: {
type: 'object',
properties: {
keyword: { type: 'string', description: 'The keyword' },
volume: { type: 'number', description: 'Monthly search volume' },
position: {
type: 'number',
description: 'Best ranking position for this keyword',
optional: true,
},
url: {
type: 'string',
description: 'The URL that ranks at the best position for this keyword',
optional: true,
},
traffic: { type: 'number', description: 'Estimated monthly organic traffic' },
keywordDifficulty: {
type: 'number',
description: 'Keyword difficulty score (0-100)',
optional: true,
},
},
},
},
},
}
+134
View File
@@ -0,0 +1,134 @@
import type { AhrefsPaidPagesParams, AhrefsPaidPagesResponse } from '@/tools/ahrefs/types'
import type { ToolConfig } from '@/tools/types'
const SELECT_FIELDS = 'url,sum_traffic,keywords,top_keyword,value,ads_count'
export const paidPagesTool: ToolConfig<AhrefsPaidPagesParams, AhrefsPaidPagesResponse> = {
id: 'ahrefs_paid_pages',
name: 'Ahrefs Paid Pages',
description:
"Get a target domain's pages that receive paid search traffic, sorted by estimated paid traffic. Returns page URLs with their paid traffic, keyword counts, and estimated spend.",
version: '1.0.0',
params: {
target: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The target domain or URL to analyze. Example: "example.com"',
},
country: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Country code for traffic data. Example: "us", "gb", "de" (default: "us")',
},
mode: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Analysis mode: domain (entire domain), prefix (URL prefix), subdomains (include all subdomains, default), exact (exact URL match)',
},
date: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Date to report metrics on, in YYYY-MM-DD format (defaults to today)',
},
limit: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Maximum number of results to return. Example: 50 (default: 1000)',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Ahrefs API Key',
},
},
request: {
url: (params) => {
const url = new URL('https://api.ahrefs.com/v3/site-explorer/paid-pages')
url.searchParams.set('target', params.target)
url.searchParams.set('select', SELECT_FIELDS)
// Date is required - default to today if not provided
const date = params.date || new Date().toISOString().split('T')[0]
url.searchParams.set('date', date)
url.searchParams.set('country', params.country || 'us')
if (params.mode) url.searchParams.set('mode', params.mode)
if (params.limit) url.searchParams.set('limit', String(params.limit))
return url.toString()
},
method: 'GET',
headers: (params) => ({
Accept: 'application/json',
Authorization: `Bearer ${params.apiKey}`,
}),
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
throw new Error(data.error?.message || data.error || 'Failed to get paid pages')
}
const paidPages = (data.pages || []).map((page: any) => ({
url: page.url ?? null,
traffic: page.sum_traffic ?? null,
keywords: page.keywords ?? null,
topKeyword: page.top_keyword ?? null,
value: typeof page.value === 'number' ? page.value / 100 : null,
adsCount: page.ads_count ?? null,
}))
return {
success: true,
output: {
paidPages,
},
}
},
outputs: {
paidPages: {
type: 'array',
description: 'List of pages receiving paid search traffic',
items: {
type: 'object',
properties: {
url: { type: 'string', description: 'The page URL', optional: true },
traffic: {
type: 'number',
description: 'Estimated monthly paid search traffic',
optional: true,
},
keywords: {
type: 'number',
description: 'Number of paid keywords the page ranks for',
optional: true,
},
topKeyword: {
type: 'string',
description: 'The top keyword driving paid traffic to this page',
optional: true,
},
value: {
type: 'number',
description: 'Estimated monthly paid traffic cost in USD',
optional: true,
},
adsCount: {
type: 'number',
description: 'Number of unique ads shown for this page',
optional: true,
},
},
},
},
},
}
@@ -0,0 +1,167 @@
import type {
AhrefsRankTrackerCompetitorsOverviewParams,
AhrefsRankTrackerCompetitorsOverviewResponse,
} from '@/tools/ahrefs/types'
import type { ToolConfig } from '@/tools/types'
const SELECT_FIELDS = 'keyword,volume,keyword_difficulty,serp_features,competitors_list'
export const rankTrackerCompetitorsOverviewTool: ToolConfig<
AhrefsRankTrackerCompetitorsOverviewParams,
AhrefsRankTrackerCompetitorsOverviewResponse
> = {
id: 'ahrefs_rank_tracker_competitors_overview',
name: 'Ahrefs Rank Tracker Competitors Overview',
description:
"Get competitor rankings for the keywords tracked in an Ahrefs Rank Tracker project: each tracked keyword's volume and difficulty alongside every competitor's position, traffic, and traffic value. This endpoint is free and does not consume API units.",
version: '1.0.0',
params: {
projectId: {
type: 'number',
required: true,
visibility: 'user-or-llm',
description: 'The Rank Tracker project ID (found in the project URL in Ahrefs)',
},
date: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Date to report rankings for, in YYYY-MM-DD format',
},
device: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Rankings device type: "desktop" or "mobile"',
},
dateCompared: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Comparison date in YYYY-MM-DD format, to compute position/traffic deltas',
},
volumeMode: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Search volume calculation: "monthly" or "average" (default: "monthly")',
},
limit: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Maximum number of results to return. Example: 50 (default: 1000)',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Ahrefs API Key',
},
},
request: {
url: (params) => {
const url = new URL('https://api.ahrefs.com/v3/rank-tracker/competitors-overview')
url.searchParams.set('project_id', String(params.projectId))
url.searchParams.set('date', params.date)
url.searchParams.set('device', params.device)
url.searchParams.set('select', SELECT_FIELDS)
if (params.dateCompared) url.searchParams.set('date_compared', params.dateCompared)
url.searchParams.set('volume_mode', params.volumeMode || 'monthly')
if (params.limit) url.searchParams.set('limit', String(params.limit))
return url.toString()
},
method: 'GET',
headers: (params) => ({
Accept: 'application/json',
Authorization: `Bearer ${params.apiKey}`,
}),
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
throw new Error(
data.error?.message || data.error || 'Failed to get rank tracker competitors overview'
)
}
const competitorKeywords = (data.keywords || []).map((item: any) => ({
keyword: item.keyword || '',
volume: item.volume ?? null,
keywordDifficulty: item.keyword_difficulty ?? null,
serpFeatures: item.serp_features ?? [],
competitorsList: (item.competitors_list || []).map((competitor: any) => ({
url: competitor.url || '',
position: competitor.position ?? null,
bestPositionKind: competitor.best_position_kind ?? null,
traffic: competitor.traffic ?? null,
value: typeof competitor.value === 'number' ? competitor.value / 100 : null,
})),
}))
return {
success: true,
output: {
competitorKeywords,
},
}
},
outputs: {
competitorKeywords: {
type: 'array',
description: 'Tracked keywords with competitor ranking data',
items: {
type: 'object',
properties: {
keyword: { type: 'string', description: 'The tracked keyword' },
volume: { type: 'number', description: 'Average monthly search volume', optional: true },
keywordDifficulty: {
type: 'number',
description: 'Keyword difficulty score (0-100)',
optional: true,
},
serpFeatures: {
type: 'array',
description: 'SERP features present in the results',
items: { type: 'string' },
},
competitorsList: {
type: 'array',
description: 'Ranking data for each tracked competitor on this keyword',
items: {
type: 'object',
properties: {
url: { type: 'string', description: "The competitor's ranking URL" },
position: {
type: 'number',
description: 'Current ranking position',
optional: true,
},
bestPositionKind: {
type: 'string',
description: 'Type of the best position achieved',
optional: true,
},
traffic: {
type: 'number',
description: 'Estimated traffic to the competitor',
optional: true,
},
value: {
type: 'number',
description: 'Estimated traffic value (USD)',
optional: true,
},
},
},
},
},
},
},
},
}
@@ -0,0 +1,132 @@
import type {
AhrefsRankTrackerCompetitorsStatsParams,
AhrefsRankTrackerCompetitorsStatsResponse,
} from '@/tools/ahrefs/types'
import type { ToolConfig } from '@/tools/types'
const SELECT_FIELDS =
'competitor,traffic,traffic_value,average_position,pos_1_3,pos_4_10,share_of_voice,share_of_traffic_value'
export const rankTrackerCompetitorsStatsTool: ToolConfig<
AhrefsRankTrackerCompetitorsStatsParams,
AhrefsRankTrackerCompetitorsStatsResponse
> = {
id: 'ahrefs_rank_tracker_competitors_stats',
name: 'Ahrefs Rank Tracker Competitors Stats',
description:
"Get aggregate competitor stats for an Ahrefs Rank Tracker project: each competitor's traffic, traffic value, average position, and share of voice across all tracked keywords. This endpoint is free and does not consume API units.",
version: '1.0.0',
params: {
projectId: {
type: 'number',
required: true,
visibility: 'user-or-llm',
description: 'The Rank Tracker project ID (found in the project URL in Ahrefs)',
},
date: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Date to report metrics for, in YYYY-MM-DD format',
},
device: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Rankings device type: "desktop" or "mobile"',
},
volumeMode: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Search volume calculation: "monthly" or "average" (default: "monthly")',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Ahrefs API Key',
},
},
request: {
url: (params) => {
const url = new URL('https://api.ahrefs.com/v3/rank-tracker/competitors-stats')
url.searchParams.set('select', SELECT_FIELDS)
url.searchParams.set('date', params.date)
url.searchParams.set('device', params.device)
url.searchParams.set('project_id', String(params.projectId))
url.searchParams.set('volume_mode', params.volumeMode || 'monthly')
return url.toString()
},
method: 'GET',
headers: (params) => ({
Accept: 'application/json',
Authorization: `Bearer ${params.apiKey}`,
}),
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
throw new Error(
data.error?.message || data.error || 'Failed to get rank tracker competitors stats'
)
}
const competitorsStats = (data['competitors-metrics'] || []).map((item: any) => ({
competitor: item.competitor || '',
traffic: item.traffic ?? null,
trafficValue: typeof item.traffic_value === 'number' ? item.traffic_value / 100 : null,
averagePosition: item.average_position ?? null,
pos1To3: item.pos_1_3 ?? 0,
pos4To10: item.pos_4_10 ?? 0,
shareOfVoice: item.share_of_voice ?? 0,
shareOfTrafficValue: item.share_of_traffic_value ?? 0,
}))
return {
success: true,
output: {
competitorsStats,
},
}
},
outputs: {
competitorsStats: {
type: 'array',
description: 'Aggregate stats for each tracked competitor',
items: {
type: 'object',
properties: {
competitor: { type: 'string', description: "The competitor's URL" },
traffic: {
type: 'number',
description: 'Estimated monthly organic visits',
optional: true,
},
trafficValue: {
type: 'number',
description: 'Estimated monthly organic traffic value (USD)',
optional: true,
},
averagePosition: {
type: 'number',
description: 'Average top organic position across tracked keywords',
optional: true,
},
pos1To3: { type: 'number', description: 'Keywords ranking in top 3 positions' },
pos4To10: { type: 'number', description: 'Keywords ranking in positions 4-10' },
shareOfVoice: { type: 'number', description: 'Organic traffic share percentage' },
shareOfTrafficValue: {
type: 'number',
description: 'Organic traffic value share percentage',
},
},
},
},
},
}
@@ -0,0 +1,149 @@
import type {
AhrefsRankTrackerOverviewParams,
AhrefsRankTrackerOverviewResponse,
} from '@/tools/ahrefs/types'
import type { ToolConfig } from '@/tools/types'
const SELECT_FIELDS =
'keyword,position,volume,keyword_difficulty,url,traffic,serp_features,best_position_kind'
export const rankTrackerOverviewTool: ToolConfig<
AhrefsRankTrackerOverviewParams,
AhrefsRankTrackerOverviewResponse
> = {
id: 'ahrefs_rank_tracker_overview',
name: 'Ahrefs Rank Tracker Overview',
description:
'Get ranking overview metrics for the keywords tracked in an Ahrefs Rank Tracker project: position, search volume, keyword difficulty, and estimated traffic. This endpoint is free and does not consume API units.',
version: '1.0.0',
params: {
projectId: {
type: 'number',
required: true,
visibility: 'user-or-llm',
description: 'The Rank Tracker project ID (found in the project URL in Ahrefs)',
},
date: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Date to report rankings for, in YYYY-MM-DD format',
},
device: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Rankings device type: "desktop" or "mobile"',
},
dateCompared: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Comparison date in YYYY-MM-DD format, to compute position/traffic deltas',
},
volumeMode: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Search volume calculation: "monthly" or "average" (default: "monthly")',
},
limit: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Maximum number of results to return. Example: 50 (default: 1000)',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Ahrefs API Key',
},
},
request: {
url: (params) => {
const url = new URL('https://api.ahrefs.com/v3/rank-tracker/overview')
url.searchParams.set('project_id', String(params.projectId))
url.searchParams.set('date', params.date)
url.searchParams.set('device', params.device)
url.searchParams.set('select', SELECT_FIELDS)
if (params.dateCompared) url.searchParams.set('date_compared', params.dateCompared)
url.searchParams.set('volume_mode', params.volumeMode || 'monthly')
if (params.limit) url.searchParams.set('limit', String(params.limit))
return url.toString()
},
method: 'GET',
headers: (params) => ({
Accept: 'application/json',
Authorization: `Bearer ${params.apiKey}`,
}),
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
throw new Error(data.error?.message || data.error || 'Failed to get rank tracker overview')
}
const overviews = (data.overviews || []).map((item: any) => ({
keyword: item.keyword || '',
position: item.position ?? null,
volume: item.volume ?? null,
keywordDifficulty: item.keyword_difficulty ?? null,
url: item.url ?? null,
traffic: item.traffic ?? null,
serpFeatures: item.serp_features ?? [],
bestPositionKind: item.best_position_kind ?? null,
}))
return {
success: true,
output: {
overviews,
},
}
},
outputs: {
overviews: {
type: 'array',
description: 'Ranking overview for each tracked keyword',
items: {
type: 'object',
properties: {
keyword: { type: 'string', description: 'The tracked keyword' },
position: {
type: 'number',
description: 'Top organic search position',
optional: true,
},
volume: { type: 'number', description: 'Average monthly search volume', optional: true },
keywordDifficulty: {
type: 'number',
description: 'Keyword difficulty score (0-100)',
optional: true,
},
url: { type: 'string', description: 'Top-ranking URL', optional: true },
traffic: {
type: 'number',
description: 'Estimated monthly organic visits',
optional: true,
},
serpFeatures: {
type: 'array',
description: 'SERP features present in the results',
items: { type: 'string' },
},
bestPositionKind: {
type: 'string',
description: 'Type of the top position (organic, paid, or SERP feature)',
optional: true,
},
},
},
},
},
}
@@ -0,0 +1,166 @@
import type {
AhrefsRankTrackerSerpOverviewParams,
AhrefsRankTrackerSerpOverviewResponse,
} from '@/tools/ahrefs/types'
import type { ToolConfig } from '@/tools/types'
export const rankTrackerSerpOverviewTool: ToolConfig<
AhrefsRankTrackerSerpOverviewParams,
AhrefsRankTrackerSerpOverviewResponse
> = {
id: 'ahrefs_rank_tracker_serp_overview',
name: 'Ahrefs Rank Tracker SERP Overview',
description:
'Get the full SERP (search engine results page) for a keyword tracked in an Ahrefs Rank Tracker project, including every ranking URL with its position, title, and authority metrics. This endpoint is free and does not consume API units.',
version: '1.0.0',
params: {
projectId: {
type: 'number',
required: true,
visibility: 'user-or-llm',
description: 'The Rank Tracker project ID (found in the project URL in Ahrefs)',
},
keyword: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The tracked keyword to retrieve SERP data for',
},
country: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Country code for the tracked keyword. Example: "us", "gb", "de"',
},
device: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Rankings device type: "desktop" or "mobile"',
},
topPositions: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Number of top organic positions to return (defaults to all available)',
},
date: {
type: 'string',
required: false,
visibility: 'user-only',
description:
'Timestamp to return the last available SERP Overview at, in YYYY-MM-DDThh:mm:ss format',
},
locationId: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Location ID of the tracked keyword, if tracked at a specific location',
},
languageCode: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Language code of the tracked keyword',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Ahrefs API Key',
},
},
request: {
url: (params) => {
const url = new URL('https://api.ahrefs.com/v3/rank-tracker/serp-overview')
url.searchParams.set('project_id', String(params.projectId))
url.searchParams.set('keyword', params.keyword)
url.searchParams.set('country', params.country)
url.searchParams.set('device', params.device)
if (params.topPositions) url.searchParams.set('top_positions', String(params.topPositions))
if (params.date) url.searchParams.set('date', params.date)
if (params.locationId) url.searchParams.set('location_id', String(params.locationId))
if (params.languageCode) url.searchParams.set('language_code', params.languageCode)
return url.toString()
},
method: 'GET',
headers: (params) => ({
Accept: 'application/json',
Authorization: `Bearer ${params.apiKey}`,
}),
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
throw new Error(data.error?.message || data.error || 'Failed to get SERP overview')
}
const positions = (data.positions || []).map((item: any) => ({
position: item.position ?? 0,
url: item.url || '',
title: item.title || '',
type: item.type ?? [],
domainRating: item.domain_rating ?? 0,
urlRating: item.url_rating ?? 0,
backlinks: item.backlinks ?? 0,
refdomains: item.refdomains ?? 0,
traffic: item.traffic ?? 0,
value: typeof item.value === 'number' ? item.value / 100 : null,
topKeyword: item.top_keyword ?? null,
topKeywordVolume: item.top_keyword_volume ?? null,
updateDate: item.update_date || '',
}))
return {
success: true,
output: {
positions,
},
}
},
outputs: {
positions: {
type: 'array',
description: 'Every ranking result on the SERP for the tracked keyword',
items: {
type: 'object',
properties: {
position: { type: 'number', description: 'Position of the result in the SERP' },
url: { type: 'string', description: 'URL of the ranking page' },
title: { type: 'string', description: 'Page title' },
type: {
type: 'array',
description: 'The kind of the position: organic, paid, or a SERP feature',
items: { type: 'string' },
},
domainRating: { type: 'number', description: 'Domain Rating of the ranking domain' },
urlRating: { type: 'number', description: 'URL Rating of the ranking page' },
backlinks: { type: 'number', description: 'Total backlinks to the ranking domain' },
refdomains: { type: 'number', description: 'Unique referring domains' },
traffic: { type: 'number', description: 'Estimated monthly organic search traffic' },
value: {
type: 'number',
description: 'Estimated monthly traffic value (USD)',
optional: true,
},
topKeyword: {
type: 'string',
description: 'Highest-traffic keyword ranking for this page',
optional: true,
},
topKeywordVolume: {
type: 'number',
description: 'Monthly search volume for the top keyword',
optional: true,
},
updateDate: { type: 'string', description: 'Date the SERP was last checked' },
},
},
},
},
}
+113
View File
@@ -0,0 +1,113 @@
import type {
AhrefsRefdomainsHistoryParams,
AhrefsRefdomainsHistoryResponse,
} from '@/tools/ahrefs/types'
import type { ToolConfig } from '@/tools/types'
export const refdomainsHistoryTool: ToolConfig<
AhrefsRefdomainsHistoryParams,
AhrefsRefdomainsHistoryResponse
> = {
id: 'ahrefs_refdomains_history',
name: 'Ahrefs Referring Domains History',
description:
'Get the historical referring domains trend for a target domain or URL over a date range, grouped daily, weekly, or monthly.',
version: '1.0.0',
params: {
target: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The target domain or URL to analyze. Example: "example.com"',
},
dateFrom: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Start date of the historical period, in YYYY-MM-DD format',
},
dateTo: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'End date of the historical period, in YYYY-MM-DD format (defaults to today)',
},
historyGrouping: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Time interval for grouping data points: "daily", "weekly", or "monthly" (default: "monthly")',
},
mode: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Analysis mode: domain (entire domain), prefix (URL prefix), subdomains (include all subdomains, default), exact (exact URL match)',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Ahrefs API Key',
},
},
request: {
url: (params) => {
const url = new URL('https://api.ahrefs.com/v3/site-explorer/refdomains-history')
url.searchParams.set('target', params.target)
url.searchParams.set('date_from', params.dateFrom)
if (params.dateTo) url.searchParams.set('date_to', params.dateTo)
if (params.historyGrouping) url.searchParams.set('history_grouping', params.historyGrouping)
if (params.mode) url.searchParams.set('mode', params.mode)
return url.toString()
},
method: 'GET',
headers: (params) => ({
Accept: 'application/json',
Authorization: `Bearer ${params.apiKey}`,
}),
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
throw new Error(
data.error?.message || data.error || 'Failed to get referring domains history'
)
}
const referringDomainsHistory = (data.refdomains || []).map((item: any) => ({
date: item.date || '',
referringDomains: item.refdomains ?? 0,
}))
return {
success: true,
output: {
referringDomainsHistory,
},
}
},
outputs: {
referringDomainsHistory: {
type: 'array',
description: 'Historical referring domains count data points',
items: {
type: 'object',
properties: {
date: { type: 'string', description: 'The date of the data point' },
referringDomains: {
type: 'number',
description: 'Total number of unique domains linking to the target on this date',
},
},
},
},
},
}
+123
View File
@@ -0,0 +1,123 @@
import type {
AhrefsReferringDomainsParams,
AhrefsReferringDomainsResponse,
} from '@/tools/ahrefs/types'
import type { ToolConfig } from '@/tools/types'
const SELECT_FIELDS = 'domain,domain_rating,links_to_target,dofollow_links,first_seen,last_seen'
export const referringDomainsTool: ToolConfig<
AhrefsReferringDomainsParams,
AhrefsReferringDomainsResponse
> = {
id: 'ahrefs_referring_domains',
name: 'Ahrefs Referring Domains',
description:
'Get a list of domains that link to a target domain or URL. Returns unique referring domains with their domain rating, backlink counts, and discovery dates.',
version: '1.0.0',
params: {
target: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description:
'The target domain or URL to analyze. Example: "example.com" or "https://example.com/page"',
},
mode: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Analysis mode: domain (entire domain), prefix (URL prefix), subdomains (include all subdomains, default), exact (exact URL match). Example: "domain"',
},
history: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Historical scope: "live" (currently live), "all_time" (default, includes lost domains), or "since:YYYY-MM-DD" (domains found since a date).',
},
limit: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Maximum number of results to return. Example: 50 (default: 1000)',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Ahrefs API Key',
},
},
request: {
url: (params) => {
const url = new URL('https://api.ahrefs.com/v3/site-explorer/refdomains')
url.searchParams.set('target', params.target)
url.searchParams.set('select', SELECT_FIELDS)
if (params.mode) url.searchParams.set('mode', params.mode)
url.searchParams.set('history', params.history || 'all_time')
if (params.limit) url.searchParams.set('limit', String(params.limit))
return url.toString()
},
method: 'GET',
headers: (params) => ({
Accept: 'application/json',
Authorization: `Bearer ${params.apiKey}`,
}),
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
throw new Error(data.error?.message || data.error || 'Failed to get referring domains')
}
const referringDomains = (data.refdomains || []).map((domain: any) => ({
domain: domain.domain || '',
domainRating: domain.domain_rating ?? 0,
backlinks: domain.links_to_target ?? 0,
dofollowBacklinks: domain.dofollow_links ?? 0,
firstSeen: domain.first_seen || '',
lastVisited: domain.last_seen ?? null,
}))
return {
success: true,
output: {
referringDomains,
},
}
},
outputs: {
referringDomains: {
type: 'array',
description: 'List of domains linking to the target',
items: {
type: 'object',
properties: {
domain: { type: 'string', description: 'The referring domain' },
domainRating: { type: 'number', description: 'Domain Rating of the referring domain' },
backlinks: {
type: 'number',
description: 'Total number of backlinks from this domain to the target',
},
dofollowBacklinks: {
type: 'number',
description: 'Number of dofollow backlinks from this domain',
},
firstSeen: { type: 'string', description: 'When the domain was first seen linking' },
lastVisited: {
type: 'string',
description: 'When the domain was last seen linking (null if never re-crawled)',
optional: true,
},
},
},
},
},
}
+139
View File
@@ -0,0 +1,139 @@
import type { AhrefsRelatedTermsParams, AhrefsRelatedTermsResponse } from '@/tools/ahrefs/types'
import type { ToolConfig } from '@/tools/types'
const SELECT_FIELDS =
'keyword,volume,difficulty,cpc,parent_topic,traffic_potential,intents,serp_features'
export const relatedTermsTool: ToolConfig<AhrefsRelatedTermsParams, AhrefsRelatedTermsResponse> = {
id: 'ahrefs_related_terms',
name: 'Ahrefs Related Terms',
description:
'Get keyword ideas related to a seed keyword: terms the same top-ranking pages also rank for ("also rank for") or also discuss ("also talk about"), with volume, difficulty, and CPC.',
version: '1.0.0',
params: {
keyword: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The seed keyword to find related terms for',
},
country: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Country code for keyword data. Example: "us", "gb", "de" (default: "us")',
},
terms: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Type of related keywords to return: "also_rank_for", "also_talk_about", or "all" (default: "all")',
},
viewFor: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Whether to derive related terms from the top 10 or top 100 ranking pages (default: "top_10")',
},
limit: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Maximum number of results to return. Example: 50 (default: 1000)',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Ahrefs API Key',
},
},
request: {
url: (params) => {
const url = new URL('https://api.ahrefs.com/v3/keywords-explorer/related-terms')
url.searchParams.set('select', SELECT_FIELDS)
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)
if (params.limit) url.searchParams.set('limit', String(params.limit))
return url.toString()
},
method: 'GET',
headers: (params) => ({
Accept: 'application/json',
Authorization: `Bearer ${params.apiKey}`,
}),
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
throw new Error(data.error?.message || data.error || 'Failed to get related terms')
}
const relatedTerms = (data.keywords || []).map((item: any) => ({
keyword: item.keyword || '',
volume: item.volume ?? null,
keywordDifficulty: item.difficulty ?? null,
cpc: typeof item.cpc === 'number' ? item.cpc / 100 : null,
parentTopic: item.parent_topic ?? null,
trafficPotential: item.traffic_potential ?? null,
intents: item.intents ?? null,
serpFeatures: item.serp_features ?? [],
}))
return {
success: true,
output: {
relatedTerms,
},
}
},
outputs: {
relatedTerms: {
type: 'array',
description: 'Related keyword ideas for the seed keyword',
items: {
type: 'object',
properties: {
keyword: { type: 'string', description: 'The related keyword' },
volume: { type: 'number', description: 'Average monthly search volume', optional: true },
keywordDifficulty: {
type: 'number',
description: 'Keyword difficulty score (0-100)',
optional: true,
},
cpc: { type: 'number', description: 'Cost per click in USD', optional: true },
parentTopic: {
type: 'string',
description: 'The parent topic for this keyword',
optional: true,
},
trafficPotential: {
type: 'number',
description: 'Estimated traffic potential if ranking #1',
optional: true,
},
intents: {
type: 'object',
description:
'Search intent flags (informational, navigational, commercial, transactional, branded, local)',
optional: true,
},
serpFeatures: {
type: 'array',
description: 'SERP features present in the results',
items: { type: 'string' },
},
},
},
},
},
}
@@ -0,0 +1,142 @@
import type {
AhrefsSiteAuditPageExplorerParams,
AhrefsSiteAuditPageExplorerResponse,
} from '@/tools/ahrefs/types'
import type { ToolConfig } from '@/tools/types'
const SELECT_FIELDS =
'url,http_code,title,internal_links,external_links,backlinks,compliant,traffic'
export const siteAuditPageExplorerTool: ToolConfig<
AhrefsSiteAuditPageExplorerParams,
AhrefsSiteAuditPageExplorerResponse
> = {
id: 'ahrefs_site_audit_page_explorer',
name: 'Ahrefs Site Audit Page Explorer',
description:
'Get crawled pages from an Ahrefs Site Audit project with health and SEO metrics: HTTP status, title, link counts, backlinks, indexability, and traffic. Optionally filter to pages affected by a specific issue.',
version: '1.0.0',
params: {
projectId: {
type: 'number',
required: true,
visibility: 'user-or-llm',
description: 'The Site Audit project ID (found in the project URL in Ahrefs)',
},
date: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Crawl date in YYYY-MM-DDThh:mm:ss format (defaults to the most recent crawl)',
},
limit: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Maximum number of results to return. Example: 50 (default: 1000)',
},
offset: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Number of results to skip, for pagination',
},
issueId: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Only return pages affected by this issue ID',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Ahrefs API Key',
},
},
request: {
url: (params) => {
const url = new URL('https://api.ahrefs.com/v3/site-audit/page-explorer')
url.searchParams.set('project_id', String(params.projectId))
url.searchParams.set('select', SELECT_FIELDS)
if (params.date) url.searchParams.set('date', params.date)
if (params.limit) url.searchParams.set('limit', String(params.limit))
if (params.offset) url.searchParams.set('offset', String(params.offset))
if (params.issueId) url.searchParams.set('issue_id', params.issueId)
return url.toString()
},
method: 'GET',
headers: (params) => ({
Accept: 'application/json',
Authorization: `Bearer ${params.apiKey}`,
}),
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
throw new Error(data.error?.message || data.error || 'Failed to get site audit pages')
}
const auditPages = (data.pages || []).map((page: any) => ({
url: page.url || '',
httpCode: page.http_code ?? null,
title: page.title ?? [],
internalLinks: (page.internal_links || []).length,
externalLinks: (page.external_links || []).length,
backlinks: page.backlinks ?? null,
compliant: page.compliant ?? null,
traffic: page.traffic ?? null,
}))
return {
success: true,
output: {
auditPages,
},
}
},
outputs: {
auditPages: {
type: 'array',
description: 'List of crawled pages with health and SEO metrics',
items: {
type: 'object',
properties: {
url: { type: 'string', description: 'The crawled page URL' },
httpCode: {
type: 'number',
description: 'HTTP status code returned by the URL',
optional: true,
},
title: {
type: 'array',
description: 'Page title tag(s)',
items: { type: 'string' },
},
internalLinks: { type: 'number', description: 'Number of internal outgoing links' },
externalLinks: { type: 'number', description: 'Number of external outgoing links' },
backlinks: {
type: 'number',
description: 'Number of incoming external links to the page',
optional: true,
},
compliant: {
type: 'boolean',
description: 'Whether the page is indexable (200 status, no canonical/noindex)',
optional: true,
},
traffic: {
type: 'number',
description: 'Estimated monthly organic traffic to the page',
optional: true,
},
},
},
},
},
}
+124
View File
@@ -0,0 +1,124 @@
import type { AhrefsTopPagesParams, AhrefsTopPagesResponse } from '@/tools/ahrefs/types'
import type { ToolConfig } from '@/tools/types'
const SELECT_FIELDS = 'url,sum_traffic,keywords,top_keyword,value'
export const topPagesTool: ToolConfig<AhrefsTopPagesParams, AhrefsTopPagesResponse> = {
id: 'ahrefs_top_pages',
name: 'Ahrefs Top Pages',
description:
'Get the top pages of a target domain sorted by organic traffic. Returns page URLs with their traffic, keyword counts, and estimated traffic value.',
version: '1.0.0',
params: {
target: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The target domain to analyze. Example: "example.com"',
},
country: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Country code for traffic data. Example: "us", "gb", "de" (default: "us")',
},
mode: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Analysis mode: domain (entire domain), prefix (URL prefix), subdomains (include all subdomains, default), exact (exact URL match). Example: "domain"',
},
date: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Date to report metrics on, in YYYY-MM-DD format (defaults to today)',
},
limit: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Maximum number of results to return. Example: 50 (default: 1000)',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Ahrefs API Key',
},
},
request: {
url: (params) => {
const url = new URL('https://api.ahrefs.com/v3/site-explorer/top-pages')
url.searchParams.set('target', params.target)
url.searchParams.set('country', params.country || 'us')
url.searchParams.set('select', SELECT_FIELDS)
// Date is required - default to today if not provided
const date = params.date || new Date().toISOString().split('T')[0]
url.searchParams.set('date', date)
if (params.mode) url.searchParams.set('mode', params.mode)
if (params.limit) url.searchParams.set('limit', String(params.limit))
return url.toString()
},
method: 'GET',
headers: (params) => ({
Accept: 'application/json',
Authorization: `Bearer ${params.apiKey}`,
}),
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
throw new Error(data.error?.message || data.error || 'Failed to get top pages')
}
const pages = (data.pages || []).map((page: any) => ({
url: page.url ?? null,
traffic: page.sum_traffic ?? 0,
keywords: page.keywords ?? null,
topKeyword: page.top_keyword ?? null,
value: typeof page.value === 'number' ? page.value / 100 : null,
}))
return {
success: true,
output: {
pages,
},
}
},
outputs: {
pages: {
type: 'array',
description: 'List of top pages by organic traffic',
items: {
type: 'object',
properties: {
url: { type: 'string', description: 'The page URL', optional: true },
traffic: { type: 'number', description: 'Estimated monthly organic traffic' },
keywords: {
type: 'number',
description: 'Number of keywords the page ranks for',
optional: true,
},
topKeyword: {
type: 'string',
description: 'The top keyword driving traffic to this page',
optional: true,
},
value: {
type: 'number',
description: 'Estimated traffic value in USD',
optional: true,
},
},
},
},
},
}
+609
View File
@@ -0,0 +1,609 @@
// Common types for Ahrefs API tools
import type { ToolResponse } from '@/tools/types'
// Common parameters for all Ahrefs tools
interface AhrefsBaseParams {
apiKey: string
}
// Target mode for analysis
export type AhrefsTargetMode = 'domain' | 'prefix' | 'subdomains' | 'exact'
// Historical scope for backlink-profile endpoints (no `date` param on these endpoints)
export type AhrefsHistory = 'live' | 'all_time' | string // `since:YYYY-MM-DD` is also valid
// Domain Rating tool types
export interface AhrefsDomainRatingParams extends AhrefsBaseParams {
target: string
date?: string // Date in YYYY-MM-DD format, defaults to today
}
export interface AhrefsDomainRatingResponse extends ToolResponse {
output: {
domainRating: number
ahrefsRank: number | null
}
}
// Backlinks tool types
export interface AhrefsBacklinksParams extends AhrefsBaseParams {
target: string
mode?: AhrefsTargetMode
history?: AhrefsHistory
limit?: number
}
interface AhrefsBacklink {
urlFrom: string
urlTo: string
anchor: string
domainRatingSource: number
isDofollow: boolean
firstSeen: string
lastVisited: string
}
export interface AhrefsBacklinksResponse extends ToolResponse {
output: {
backlinks: AhrefsBacklink[]
}
}
// Backlinks Stats tool types
export interface AhrefsBacklinksStatsParams extends AhrefsBaseParams {
target: string
mode?: AhrefsTargetMode
date?: string // Date in YYYY-MM-DD format, defaults to today
}
interface AhrefsBacklinksStatsResult {
liveBacklinks: number
liveReferringDomains: number
allTimeBacklinks: number
allTimeReferringDomains: number
}
export interface AhrefsBacklinksStatsResponse extends ToolResponse {
output: {
stats: AhrefsBacklinksStatsResult
}
}
// Referring Domains tool types
export interface AhrefsReferringDomainsParams extends AhrefsBaseParams {
target: string
mode?: AhrefsTargetMode
history?: AhrefsHistory
limit?: number
}
interface AhrefsReferringDomain {
domain: string
domainRating: number
backlinks: number
dofollowBacklinks: number
firstSeen: string
lastVisited: string | null
}
export interface AhrefsReferringDomainsResponse extends ToolResponse {
output: {
referringDomains: AhrefsReferringDomain[]
}
}
// Organic Keywords tool types
export interface AhrefsOrganicKeywordsParams extends AhrefsBaseParams {
target: string
country?: string
mode?: AhrefsTargetMode
date?: string // Date in YYYY-MM-DD format, defaults to today
limit?: number
}
interface AhrefsOrganicKeyword {
keyword: string
volume: number
position: number | null
url: string | null
traffic: number
keywordDifficulty: number | null
}
export interface AhrefsOrganicKeywordsResponse extends ToolResponse {
output: {
keywords: AhrefsOrganicKeyword[]
}
}
// Top Pages tool types
export interface AhrefsTopPagesParams extends AhrefsBaseParams {
target: string
country?: string
mode?: AhrefsTargetMode
date?: string // Date in YYYY-MM-DD format, defaults to today
limit?: number
}
interface AhrefsTopPage {
url: string | null
traffic: number
keywords: number | null
topKeyword: string | null
value: number | null
}
export interface AhrefsTopPagesResponse extends ToolResponse {
output: {
pages: AhrefsTopPage[]
}
}
// Keyword Overview tool types
export interface AhrefsKeywordOverviewParams extends AhrefsBaseParams {
keyword: string
country?: string
}
interface AhrefsKeywordIntents {
informational: boolean
navigational: boolean
commercial: boolean
transactional: boolean
branded: boolean
local: boolean
}
interface AhrefsKeywordOverviewResult {
keyword: string
searchVolume: number
keywordDifficulty: number | null
cpc: number | null
clicks: number | null
clicksPercentage: number | null
parentTopic: string | null
trafficPotential: number | null
intents: AhrefsKeywordIntents | null
}
export interface AhrefsKeywordOverviewResponse extends ToolResponse {
output: {
overview: AhrefsKeywordOverviewResult
}
}
// Broken Backlinks tool types
export interface AhrefsBrokenBacklinksParams extends AhrefsBaseParams {
target: string
mode?: AhrefsTargetMode
limit?: number
}
interface AhrefsBrokenBacklink {
urlFrom: string
urlTo: string
httpCode: number | null
anchor: string
domainRatingSource: number
}
export interface AhrefsBrokenBacklinksResponse extends ToolResponse {
output: {
brokenBacklinks: AhrefsBrokenBacklink[]
}
}
// Metrics tool types (single-call organic + paid search overview)
export interface AhrefsMetricsParams extends AhrefsBaseParams {
target: string
country?: string
mode?: AhrefsTargetMode
date?: string // Date in YYYY-MM-DD format, defaults to today
}
interface AhrefsMetricsResult {
organicTraffic: number
organicKeywords: number
organicKeywordsTop3: number
organicCost: number | null
paidTraffic: number
paidKeywords: number
paidPages: number
paidCost: number | null
}
export interface AhrefsMetricsResponse extends ToolResponse {
output: {
metrics: AhrefsMetricsResult
}
}
// Organic Competitors tool types
export interface AhrefsOrganicCompetitorsParams extends AhrefsBaseParams {
target: string
country?: string
mode?: AhrefsTargetMode
date?: string // Date in YYYY-MM-DD format, defaults to today
limit?: number
}
interface AhrefsOrganicCompetitor {
domain: string | null
domainRating: number
commonKeywords: number
targetKeywords: number
competitorKeywords: number
traffic: number | null
}
export interface AhrefsOrganicCompetitorsResponse extends ToolResponse {
output: {
competitors: AhrefsOrganicCompetitor[]
}
}
// Rank Tracker device type
export type AhrefsRankTrackerDevice = 'desktop' | 'mobile'
// Rank Tracker search volume calculation mode
export type AhrefsVolumeMode = 'monthly' | 'average'
// Rank Tracker Overview tool types
export interface AhrefsRankTrackerOverviewParams extends AhrefsBaseParams {
projectId: number
date: string // Date in YYYY-MM-DD format (required by the API)
device: AhrefsRankTrackerDevice
dateCompared?: string
volumeMode?: AhrefsVolumeMode
limit?: number
}
interface AhrefsRankTrackerOverviewItem {
keyword: string
position: number | null
volume: number | null
keywordDifficulty: number | null
url: string | null
traffic: number | null
serpFeatures: string[]
bestPositionKind: string | null
}
export interface AhrefsRankTrackerOverviewResponse extends ToolResponse {
output: {
overviews: AhrefsRankTrackerOverviewItem[]
}
}
// Rank Tracker SERP Overview tool types
export interface AhrefsRankTrackerSerpOverviewParams extends AhrefsBaseParams {
projectId: number
keyword: string
country: string
device: AhrefsRankTrackerDevice
topPositions?: number
date?: string // ISO date-time (YYYY-MM-DDThh:mm:ss)
locationId?: number
languageCode?: string
}
interface AhrefsSerpPosition {
position: number
url: string
title: string
type: string[]
domainRating: number
urlRating: number
backlinks: number
refdomains: number
traffic: number
value: number | null
topKeyword: string | null
topKeywordVolume: number | null
updateDate: string
}
export interface AhrefsRankTrackerSerpOverviewResponse extends ToolResponse {
output: {
positions: AhrefsSerpPosition[]
}
}
// Rank Tracker Competitors Overview tool types
export interface AhrefsRankTrackerCompetitorsOverviewParams extends AhrefsBaseParams {
projectId: number
date: string
device: AhrefsRankTrackerDevice
dateCompared?: string
volumeMode?: AhrefsVolumeMode
limit?: number
}
interface AhrefsCompetitorListItem {
url: string
position: number | null
bestPositionKind: string | null
traffic: number | null
value: number | null
}
interface AhrefsRankTrackerCompetitorsOverviewItem {
keyword: string
volume: number | null
keywordDifficulty: number | null
serpFeatures: string[]
competitorsList: AhrefsCompetitorListItem[]
}
export interface AhrefsRankTrackerCompetitorsOverviewResponse extends ToolResponse {
output: {
competitorKeywords: AhrefsRankTrackerCompetitorsOverviewItem[]
}
}
// Rank Tracker Competitors Stats tool types
export interface AhrefsRankTrackerCompetitorsStatsParams extends AhrefsBaseParams {
projectId: number
date: string
device: AhrefsRankTrackerDevice
volumeMode?: AhrefsVolumeMode
}
interface AhrefsCompetitorStat {
competitor: string
traffic: number | null
trafficValue: number | null
averagePosition: number | null
pos1To3: number
pos4To10: number
shareOfVoice: number
shareOfTrafficValue: number
}
export interface AhrefsRankTrackerCompetitorsStatsResponse extends ToolResponse {
output: {
competitorsStats: AhrefsCompetitorStat[]
}
}
// Batch Analysis tool types
export interface AhrefsBatchAnalysisParams extends AhrefsBaseParams {
targets: string // Comma-separated list of domains/URLs
mode?: AhrefsTargetMode
protocol?: 'both' | 'http' | 'https'
country?: string
volumeMode?: AhrefsVolumeMode
}
interface AhrefsBatchAnalysisResult {
url: string
index: number
domainRating: number | null
ahrefsRank: number | null
backlinks: number | null
referringDomains: number | null
organicTraffic: number | null
organicKeywords: number | null
paidTraffic: number | null
error: string | null
}
export interface AhrefsBatchAnalysisResponse extends ToolResponse {
output: {
results: AhrefsBatchAnalysisResult[]
}
}
// Site Audit Page Explorer tool types
export interface AhrefsSiteAuditPageExplorerParams extends AhrefsBaseParams {
projectId: number
date?: string // ISO date-time (YYYY-MM-DDThh:mm:ss), defaults to most recent crawl
limit?: number
offset?: number
issueId?: string
}
interface AhrefsPageExplorerResult {
url: string
httpCode: number | null
title: string[]
internalLinks: number
externalLinks: number
backlinks: number | null
compliant: boolean | null
traffic: number | null
}
export interface AhrefsSiteAuditPageExplorerResponse extends ToolResponse {
output: {
auditPages: AhrefsPageExplorerResult[]
}
}
// Domain Rating History tool types
export interface AhrefsDomainRatingHistoryParams extends AhrefsBaseParams {
target: string
dateFrom: string
dateTo?: string
historyGrouping?: 'daily' | 'weekly' | 'monthly'
}
interface AhrefsDomainRatingHistoryItem {
date: string
domainRating: number
}
export interface AhrefsDomainRatingHistoryResponse extends ToolResponse {
output: {
domainRatings: AhrefsDomainRatingHistoryItem[]
}
}
// Metrics History tool types
export interface AhrefsMetricsHistoryParams extends AhrefsBaseParams {
target: string
dateFrom: string
dateTo?: string
volumeMode?: AhrefsVolumeMode
historyGrouping?: 'daily' | 'weekly' | 'monthly'
country?: string
mode?: AhrefsTargetMode
}
interface AhrefsMetricsHistoryItem {
date: string
organicTraffic: number
organicCost: number | null
paidTraffic: number
paidCost: number | null
}
export interface AhrefsMetricsHistoryResponse extends ToolResponse {
output: {
metricsHistory: AhrefsMetricsHistoryItem[]
}
}
// Referring Domains History tool types
export interface AhrefsRefdomainsHistoryParams extends AhrefsBaseParams {
target: string
dateFrom: string
dateTo?: string
historyGrouping?: 'daily' | 'weekly' | 'monthly'
mode?: AhrefsTargetMode
}
interface AhrefsRefdomainsHistoryItem {
date: string
referringDomains: number
}
export interface AhrefsRefdomainsHistoryResponse extends ToolResponse {
output: {
referringDomainsHistory: AhrefsRefdomainsHistoryItem[]
}
}
// Keywords History tool types
export interface AhrefsKeywordsHistoryParams extends AhrefsBaseParams {
target: string
dateFrom: string
dateTo?: string
historyGrouping?: 'daily' | 'weekly' | 'monthly'
country?: string
mode?: AhrefsTargetMode
}
interface AhrefsKeywordsHistoryItem {
date: string
top3: number
top4To10: number
top11To20: number
top21To50: number
top51Plus: number
}
export interface AhrefsKeywordsHistoryResponse extends ToolResponse {
output: {
keywordsHistory: AhrefsKeywordsHistoryItem[]
}
}
// Related Terms tool types
export interface AhrefsRelatedTermsParams extends AhrefsBaseParams {
keyword: string
country?: string
terms?: 'also_rank_for' | 'also_talk_about' | 'all'
viewFor?: 'top_10' | 'top_100'
limit?: number
}
interface AhrefsRelatedTerm {
keyword: string
volume: number | null
keywordDifficulty: number | null
cpc: number | null
parentTopic: string | null
trafficPotential: number | null
intents: Record<string, boolean> | null
serpFeatures: string[]
}
export interface AhrefsRelatedTermsResponse extends ToolResponse {
output: {
relatedTerms: AhrefsRelatedTerm[]
}
}
// Anchors tool types
export interface AhrefsAnchorsParams extends AhrefsBaseParams {
target: string
mode?: AhrefsTargetMode
history?: AhrefsHistory
limit?: number
}
interface AhrefsAnchor {
anchor: string
backlinks: number
dofollowBacklinks: number
referringDomains: number
firstSeen: string
lastSeen: string | null
}
export interface AhrefsAnchorsResponse extends ToolResponse {
output: {
anchors: AhrefsAnchor[]
}
}
// Paid Pages tool types
export interface AhrefsPaidPagesParams extends AhrefsBaseParams {
target: string
country?: string
mode?: AhrefsTargetMode
date?: string // Date in YYYY-MM-DD format, defaults to today
limit?: number
}
interface AhrefsPaidPage {
url: string | null
traffic: number | null
keywords: number | null
topKeyword: string | null
value: number | null
adsCount: number | null
}
export interface AhrefsPaidPagesResponse extends ToolResponse {
output: {
paidPages: AhrefsPaidPage[]
}
}
// Union type for all possible responses
export type AhrefsResponse =
| AhrefsDomainRatingResponse
| AhrefsBacklinksResponse
| AhrefsBacklinksStatsResponse
| AhrefsReferringDomainsResponse
| AhrefsOrganicKeywordsResponse
| AhrefsTopPagesResponse
| AhrefsKeywordOverviewResponse
| AhrefsBrokenBacklinksResponse
| AhrefsMetricsResponse
| AhrefsOrganicCompetitorsResponse
| AhrefsRankTrackerOverviewResponse
| AhrefsRankTrackerSerpOverviewResponse
| AhrefsRankTrackerCompetitorsOverviewResponse
| AhrefsRankTrackerCompetitorsStatsResponse
| AhrefsBatchAnalysisResponse
| AhrefsSiteAuditPageExplorerResponse
| AhrefsDomainRatingHistoryResponse
| AhrefsMetricsHistoryResponse
| AhrefsRefdomainsHistoryResponse
| AhrefsKeywordsHistoryResponse
| AhrefsRelatedTermsResponse
| AhrefsAnchorsResponse
| AhrefsPaidPagesResponse