jeffersongoncalves/laravel-dataforseo
Laravel DataForSEO is a clean integration for the DataForSEO API, letting you query SERP results, keywords, backlinks, and on-page audits from your Laravel apps. Configure credentials once and use a simple, expressive client to pull SEO data into your projects.
The package is a fluent HTTP client, not an abstraction layer — treat it as a thin, well-typed wrapper around DataForSEO's REST API and design your own domain layer on top.
Minimal setup:
composer require the package, then publish its config (php artisan vendor:publish --tag=...) and review config/dataforseo.php before touching any endpoint class. The config is the map of the whole package: base URL, sandbox toggle, timeout, retry policy, and credentials..env (DATAFORSEO_LOGIN / DATAFORSEO_PASSWORD). DataForSEO uses HTTP Basic auth with account login + password, not a bearer API key — confirm the exact env keys against the config file, since this is the #1 source of 401s.php artisan config:clear after editing. If the app uses config:cache in deploy, verify the credentials are read at resolve time, not boot time.Where to look first: the service provider (to see whether you get a facade, an injectable singleton, or both), then the endpoint namespace (Serp, KeywordsData, Backlinks, OnPage, Labs). Read one SERP class end-to-end — it's the smallest surface and mirrors the shape of the others.
First use case: a single live SERP lookup for one keyword to prove auth and response parsing work, then immediately move it into a queued job. Do not build a feature on a synchronous controller call; DataForSEO latency is measured in seconds, and several endpoints are task-based (submit → poll/callback) rather than request/response.
Wrap the fluent client in your own service. Controllers and Livewire components should never see the package's builder — inject a SerpService / BacklinkService that returns your DTOs. This keeps the fluent chain (which changes shape per endpoint) contained in one file per capability and makes swapping to Http::fake() or a sandbox trivial.
Assume task-based semantics for anything expensive. DataForSEO has two modes: live (one call, results inline, higher cost per call) and standard/queued (submit a task, receive a task ID, then retrieve results, or receive a postback). For anything user-facing and interactive, live is correct. For bulk work — a nightly rank check across 500 keywords, an OnPage crawl, a Labs pull — use the task pattern: dispatch a job that submits, persist the task ID on your model, and either poll from a scheduled command or register a postback route. The postback route should be excluded from CSRF, idempotent, and verify the payload against the task ID you stored rather than trusting the body.
Normalize and persist raw responses. Store the full JSON in a json column alongside a normalized row (keyword, location, rank, url, checked_at). You are paying per request; the raw blob is your audit trail, your re-processing path when parsing logic changes, and your defence when DataForSEO changes a field.
Cache aggressively where the data is stable. SERP positions are volatile — cache minutes, not hours. Keywords Data (search volume), Labs, and much of Backlinks are stable for weeks; cache them for days and key the cache on the full parameter set (keyword + location + language + device + depth), not just the keyword.
Batch and throttle deliberately. Labs and Keywords Data accept multiple keywords per call and are dramatically cheaper per keyword that way. Pair batching with a Redis RateLimiter on the job middleware so concurrent workers don't blow through the account's rate limit, and set $tries = 1 on any job that submits a billable task.
Test against a fake, never the live API. Bind a fake implementation of your service interface in the container, or use Laravel's Http::fake() with recorded fixtures captured once from a real (cheap) call. If the package exposes a sandbox flag, wire it to app()->environment('local') and assert in a test that no live credentials are reachable from the test suite.
artisan tinker experiments against production credentials, or CI. Gate bulk operations behind an explicit flag or an artisan command with a confirmation prompt.20000-range code for OK, 40000-range for errors, plus per-task statuses). A 200 response can contain a fully failed task. Parse the status code and message and throw your own exception; don't rely on the package surfacing every failure as an HTTP error.null or absent for low-volume keywords or unsupported locations. Use data_get() or null-safe accessors everywhere rather than array chains.debug level for every call. When a bulk job produces partial results, the task ID is the only thing that lets you reproduce the exact request in the DataForSEO dashboard.How can I help you explore Laravel packages today?