Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Ahrefs Laravel Package

jeffersongoncalves/laravel-ahrefs

A Laravel wrapper for the Ahrefs API that provides a configurable client for fetching SEO data such as backlinks, keyword metrics, and site analytics, simplifying authentication and API requests inside Laravel applications.

View on GitHub
Deep Wiki
Context7

Getting Started

  1. composer require the package, then publish its config: php artisan vendor:publish --tag=ahrefs-config (confirm the exact tag in the README — tags vary).
  2. Add AHREFS_API_TOKEN= to .env. The token comes from Ahrefs → Account settings → API keys, and the account must be on a plan that includes API access. Note that v3 bills units per row returned, not per request — this is a paid-per-call integration, not a free lookup.
  3. Look first at, in order: config/ahrefs.php (base URL, token key, timeout, default limit), the main client/service class, then the per-endpoint classes for the eight covered reports. The config file is where you'll spend most of your tuning time.
  4. First use case: domain rating + referring domains for a list of prospect domains. It exercises auth, the target/mode resolution, and pagination without burning the most expensive units.

The package is a thin, endpoint-per-report wrapper over Ahrefs API v3. It does not model responses as DTOs or persist anything — expect it to hand you decoded arrays and leave shaping, caching, and storage to you.

Implementation Patterns

Inject, don't resolve in loops. Bind the client once via constructor injection (or the facade if provided) in a dedicated action/service class per report. Controllers should never call the API directly; you want one place to add logging, caching, and budget checks.

One action class per report type. GetDomainRating, GetOrganicKeywords, GetSerpOverview, etc. Each takes a small options object or typed args, calls the client, and returns a normalized array/DTO with the fields your app actually uses. Ahrefs field names are verbose and occasionally nested; normalizing at the boundary keeps views and jobs clean and insulates you from response changes.

Cache by (report, target, mode, date) composite key. Domain rating and backlink counts move on a daily-to-weekly cadence — Cache::remember at 12–24h is fine and cuts units dramatically. Keyword and SERP data are more volatile and more expensive; cache 6–24h but never serve SERP overview from cache when the user expects "now." Put the TTLs in config so you can tune without a deploy.

Paginate explicitly and cap it. v3 uses limit/offset; loop until the returned row count is less than your page size. Always set a hard max-page guard (e.g. 10) — a runaway loop on a broad mode like subdomains can consume a month of units in one job. Set a conservative default limit in config and raise it per-call.

Queue anything above a handful of calls. Ahrefs has no multi-target batch on most v3 endpoints, so bulk work is N requests. Use Bus::batch() over chunked target lists, give each job a $timeout above the HTTP timeout, and add job middleware that calls $job->release($backoff) on 429/5xx with exponential backoff. Combine with Laravel's RateLimiter keyed on the account token so concurrent workers don't trip the plan limit.

Track units as a first-class metric. v3 responses carry metadata about rows/units consumed. Log it per request to a table or a log channel with the endpoint and target, and add a config kill-switch (ahrefs.budget.daily_units) checked before dispatch. This is the single most valuable habit with this API — surprises here are billable.

Persist snapshots instead of re-querying. A daily scheduled job writing domain_metrics rows gives you trend charts and historical comparisons for free, and means your UI reads Eloquent, never Ahrefs. Backfill deliberately — historical date values cost the same units as current ones.

Test with Http::fake() and saved fixtures. Capture real responses once into tests/Fixtures/ahrefs/*.json and drive the suite from those. Never let CI touch the live API. Assert on your normalized DTOs, not the raw payload, so a fixture refresh doesn't break every test.

Gotchas and Tips

  • target and mode must agree. example.com, www.example.com, and https://example.com/path return materially different data, and mode (exact, prefix, domain, subdomains) changes the scope of every Site Explorer report. Normalize targets (strip scheme, lowercase, decide on www) in one helper before it ever reaches the client, or you'll get "wrong numbers" bug reports that are actually correct API behavior.

  • date is not optional on most endpoints and is strict about format. Use Y-m-d. How far back you can query depends on your plan's history retention — an out-of-range date typically errors rather than returning empty.

  • limit has a ceiling. Ahrefs caps it (commonly 1000 for most reports). Values above the cap are rejected or silently clamped; don't assume your limit: 5000 means one call.

  • Distinguish 401 from 403 and from 200-with-empty-rows. 401 = bad/expired token (fail loudly, alert). 403 = plan doesn't include the endpoint or units exhausted (don't retry — it won't recover). Empty rows on a 200 means "no data for this target/date," which is a legitimate answer — and the one you most want to avoid caching for 24h, since it will look like a permanent zero.

  • Set both timeout and connect_timeout in config. Some v3 endpoints (SERP overview, organic keywords on large domains) are genuinely slow. Default Laravel HTTP timeouts will bite you at the worst moment.

  • config:cache freezes your .env. Rotating the token in production requires php artisan config:clear / re-cache. This trips people up during incident response.

  • Don't log the token or full request URLs if you append it as a query param anywhere. Use the Authorization: Bearer header path the package provides, and add a logging middleware that redacts it.

  • Extension points: the config-driven base URL and token key mean you can point at a mock server in local/CI without touching code. For observability, wrap the underlying HTTP client (Laravel's global Http::globalMiddleware() works if the package uses the HTTP facade; otherwise subclass the client and rebind it in a service provider). For retries, prefer job middleware over in-request retry so you don't hold a web worker during backoff.

  • Version pinning. v1.0.0 covers eight endpoints; expect later minors to add more. Pin ^1.0 and read changelogs before jumping minors, since endpoint method signatures are the most likely thing to shift.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
ably/pubsub-server
mstfkhazaal/defender
mfonte/base62x
karnoweb/metapilot
tobya/bcsapiwrapper
swalker2/cpanel
vish4395/laravel-translation-manager
morningtrain/economic
teksite/systeminfo-laravel
atomcms/voting
run6/weather
siokas/laravelembeddirectives
adamlien/pkuuids
gilsonsouza/lara-doc-generator
manelgavalda/enrollment_mobile
unabomber/timezone
delatbabel/contacts
astritzeqiri/g-recaptcha
kevinongko/laravel-genode
developeruz/laravel-analytics