Multiple domains and locales¶
One application, several hosts¶
Every host gets its own key (engines verify https://<host>/<key>.txt on the submitted host):
'key' => env('INDEXNOW_KEY'), // www.example.com, the base_url host
'base_url' => 'https://www.example.com',
'hosts' => [
'example.de' => env('INDEXNOW_KEY_DE'),
'shop.example.com' => [
'key' => env('INDEXNOW_KEY_SHOP'),
'base_url' => 'https://shop.example.com', // origin for this host's URLs outside requests
'engines' => ['yandex', 'bing'], // per-host engine list
],
],
'strict_hosts' => true, // hosts not listed are skipped, not sent under the default key
The key file route serves each host's own key only (a request for example.de's key on www.example.com is 404)
and answers with Vary: Host, so a shared CDN never caches one host's file for another. indexnow:check fetches
every host's key file; --host=example.de limits it to one.
Rules on another host¶
#[IndexNow(route: 'products.show', params: ['product' => 'self'], host: 'shop.example.com')]
host can also be an accessor (host: 'tenant.domain') for multi-tenant models. The URL is generated through the
route and rebased onto hosts.<host>.base_url, else https://<host>. A route with its own Route::domain() keeps
that domain.
Locales¶
'router' => ['locales' => ['en', 'de'], 'locale_parameter' => 'locale', 'set_app_locale' => true],
'locale_hosts' => ['de' => 'example.de'], // optional: one host per locale
#[IndexNow(route: 'articles.show', params: ['article' => 'self'], locales: 'all')]
locales: 'current'(default) generates one URL;'all'one perrouter.locales; a list as given.- The locale is added as the
router.locale_parameterroute parameter only when the route declares it (/{locale}/articles/{article}), so no query string sneaks in. Withset_app_locale,App::setLocale()is switched for the duration of the generation and restored, which is what packages with localized slugs read. - With
locale_hosts, a rule withouthostgenerates each locale on that locale's host and under that host's key.
Origin of generated URLs¶
| Context | Origin |
|---|---|
| HTTP request | whatever Laravel generated (the request host) |
| artisan, queue worker | base_url (Laravel's console request is APP_URL; the package rebases scheme, host and port) |
rule with host: |
hosts.<host>.base_url, else https://<host> |
route with Route::domain() |
the route's domain, always |
A staging copy reached under another hostname would otherwise submit its URLs under the production key; that is what
strict_hosts: true prevents, and why indexnow:check warns when it is off in production.
www and apex¶
example.com and www.example.com are two hosts to IndexNow: each needs its own key file, and a URL submitted
under the other one's key answers 422. Pick the canonical one (the one your pages link to and <link
rel="canonical"> names), put it in base_url, redirect the other with 301, and do not list it in hosts —
listing both would announce two copies of every page. With strict_hosts: true a request that reached the
application under the non-canonical name submits nothing instead of announcing duplicates.
hreflang clusters¶
Localized pages that point at each other with hreflang are one cluster to the engines: when one changes, announce
the cluster. A rule with locales: 'all' does that for the locales of one model; for locales living on other hosts
locale_hosts sends each locale to its host under that host's key. When translations are separate objects, via:
walks to them:
#[IndexNow(route: 'article_show', params: ['slug' => 'slug'], locales: 'all')] // every locale of this article
#[IndexNow(via: 'translations')] // or: the sibling objects' own rules