jeffersongoncalves/laravel-keywords-everywhere
Laravel Keywords Everywhere lets you attach and manage keywords on any Eloquent model via a reusable polymorphic relationship, making it easy to add searchable tags, SEO keywords, or metadata anywhere in your app with minimal setup.
This is the initial release, so treat it as a greenfield integration rather than an upgrade. Install the package, publish the config, and wire in your API key before touching any endpoint.
composer require <vendor>/keywords-everywhere
php artisan vendor:publish --tag=keywords-everywhere-config
Add your credentials to .env (the config file is the source of truth—check it first for the exact key names and any base-URI override):
KEYWORDS_EVERYWHERE_API_KEY=your-key-here
Then confirm connectivity and quota before building anything else. credits() is the cheapest possible smoke test: it validates your key, your network path, and your remaining balance in one call.
use KeywordsEverywhere\Facades\KeywordsEverywhere;
$credits = KeywordsEverywhere::credits();
The right first use case is a single keyword lookup to see the response shape you'll actually be persisting:
$data = KeywordsEverywhere::keywordData(['laravel developer']);
Where to look first:
credits() and countries()/currencies() endpoints—these are static reference data and reveal the envelope/pagination conventions used across the client.Because every call costs credits, do not explore interactively against production data. Seed a small fixture set and cache it locally.
The API surface splits cleanly into four families, and the day-to-day work is mostly about routing each family to the right layer.
Keyword research (expensive, volatile). keywordData(), relatedKeywords(), and pasfKeywords() are the workhorses. They belong behind a service class, never called directly from a controller or a Blade view. Wrap them so you own the method names and can swap providers later:
final class KeywordResearchService
{
public function volumeFor(array $keywords): array
{
return Cache::remember(
'kw:' . md5(implode(',', $keywords)),
now()->addDays(30),
fn () => KeywordsEverywhere::keywordData($keywords),
);
}
}
Batch where the API permits it. A keyword tool that loops one call per keyword will burn credits and hit rate limits within a single page load; most of these endpoints accept a set of terms.
Domain and URL research (reporting, not request-path). domainKeywords(), domainTraffic(), domainBacklinks(), and their URL equivalents return large, slow-changing payloads. Drive these from queued jobs into your own tables, not from a web request. A nightly job that refreshes tracked competitors is the natural pattern:
class RefreshDomainMetrics implements ShouldQueue
{
public function handle(): void
{
foreach (TrackedDomain::pluck('domain') as $domain) {
DomainMetric::updateOrCreate(
['domain' => $domain],
['payload' => KeywordsEverywhere::domainTraffic($domain), 'fetched_at' => now()],
);
}
}
}
Account endpoints (guard rails). credits() should be a scheduled check plus a pre-flight assertion in any bulk job—fail fast with a clear message rather than burning through a queue of jobs that all 402 halfway down. countries() and currencies() are effectively static; cache them for the process lifetime or a day, and use them to validate user input before spending credits on a malformed locale.
Integration tips. Bind the facade behind an interface in your container so tests can fake it; the Pest suite in the package shows the expected shapes, but you want your own fakes for offline CI. Log every call with the endpoint, cost, and returned credit balance—credits() deltas are the only reliable way to audit runaway spend.
null, or returns an empty array—each requires different caller logic.config/app.php, watch for collisions in projects that already have a Keywords or KeywordsEverywhere alias. Prefer a container binding plus constructor injection in anything long-lived.keywordData(['a','b']) and keywordData(['b','a']) are different cache keys if you naively hash the array. Sort and normalise inputs before keying.Http call using the same API key and base URL from the config so credentials stay in one place.^1.0 and read the changelog before minor bumps, especially around method signatures that take arrays.credits() on every failure: it distinguishes auth problems from query problems from quota exhaustion faster than reading a stack trace.How can I help you explore Laravel packages today?