indexnow-api 1.1.0

IndexNow API client for Rust: instantly notify Bing, Yandex, Naver, Seznam.cz and Yep about new, updated or deleted URLs (async, reqwest based)
Documentation

indexnow-api – IndexNow client for Rust

Crates.io Documentation License: MIT

Async Rust library for the IndexNow protocol. Tell Microsoft Bing, Yandex, Naver, Seznam.cz and Yep about new, updated or deleted URLs the moment they change, instead of waiting for the next crawl.

  • One call, every engine – submit to api.indexnow.org and the notification is shared with all IndexNow search engines, or target a single engine directly.
  • Async / await – built on reqwest; runs on Tokio or any other async runtime.
  • Small API – one struct, four methods, one error type. No configuration files.
  • Batch friendly – up to 10,000 URLs per request, as required by the protocol.

Installation

[dependencies]
indexnow-api = "1"
tokio = { version = "1", features = ["full"] }

Requires Rust 2024 edition (Rust 1.85 or newer).

Quick start

use indexnow_api::IndexNowApi;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // host: your site's hostname
    // key:  your IndexNow key, also served at https://www.example.com/<key>.txt
    let api = IndexNowApi::new("www.example.com", "7be9fca90b3b4b039983fa8f06e03ee8");

    api.send_urls(vec![
        "https://www.example.com/new-page",
        "https://www.example.com/updated-article",
    ])
    .await?;

    println!("URLs submitted to IndexNow");
    Ok(())
}

send_urls accepts any Vec<T> where T: ToString, so &str, String and your own URL types all work.

Usage

Target one search engine

By default requests go to https://api.indexnow.org, which forwards the submission to every participating engine. To submit to one engine only, pass its origin. The crate appends the /IndexNow path for you.

use indexnow_api::IndexNowApi;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mut api = IndexNowApi::new("www.example.com", "7be9fca90b3b4b039983fa8f06e03ee8");

    api.set_search_engine("https://www.bing.com");

    api.send_urls(vec!["https://www.example.com/important-update"]).await?;
    Ok(())
}
Search engine Value for set_search_engine
All engines (default) https://api.indexnow.org
Microsoft Bing https://www.bing.com
Yandex https://yandex.com
Naver https://searchadvisor.naver.com
Seznam.cz https://search.seznam.cz
Yep https://indexnow.yep.com

Key file at a custom location

If the key file is not at https://<host>/<key>.txt, tell the search engine where it is:

use indexnow_api::IndexNowApi;

let mut api = IndexNowApi::new("www.example.com", "7be9fca90b3b4b039983fa8f06e03ee8");
api.set_key_location("https://www.example.com/keys/7be9fca90b3b4b039983fa8f06e03ee8.txt");

Error handling

send_urls returns Result<(), IndexNowError>. The error implements std::error::Error and Display, so it works with ?, anyhow, Box<dyn Error> and friends.

use indexnow_api::{IndexNowError, IndexNowApi};

#[tokio::main]
async fn main() {
    let api = IndexNowApi::new("www.example.com", "7be9fca90b3b4b039983fa8f06e03ee8");

    match api.send_urls(vec!["https://www.example.com/page"]).await {
        Ok(()) => println!("submitted"),
        Err(IndexNowError::Connection(msg)) => eprintln!("request failed: {msg}"),
        Err(IndexNowError::Status { code, body }) => eprintln!("HTTP {code}: {body}"),
    }
}
  • IndexNowError::Connection(String) – the request could not be sent (DNS, TLS, timeout) or the response could not be read.
  • IndexNowError::Status { code, body } – the search engine answered with a status other than 200 or 202. body is the response text, which usually explains the problem (invalid key, URL not on host, too many requests, ...).

API reference

Full documentation with all signatures is on docs.rs.

Item Description
IndexNowApi::new(host, key) Create a client for one site and key. Endpoint defaults to https://api.indexnow.org.
set_search_engine(origin) Submit to a specific engine (see table above).
set_key_location(url) Full URL of the key file, when it is not https://<host>/<key>.txt.
send_urls(urls).await Send one POST /IndexNow request with up to 10,000 URLs from host.
IndexNowError Error type (Connection or Status { code, body }); implements std::error::Error.

Setting up an IndexNow key

  1. Generate a key. 8 to 128 characters from a-z, A-Z, 0-9 and -. A 32-character hex string is common:

    openssl rand -hex 16
    # 7be9fca90b3b4b039983fa8f06e03ee8
    
  2. Host the key file. Create a UTF-8 text file whose only content is the key and serve it at https://www.example.com/7be9fca90b3b4b039983fa8f06e03ee8.txt. Any other location works with set_key_location.

  3. Submit a URL with the code above. HTTP 200 or 202 means the request was accepted. The key file is verified by the search engine asynchronously; an invalid key shows up later in Bing Webmaster Tools or Yandex Webmaster.

FAQ

What is IndexNow? An open protocol, started by Microsoft Bing and Yandex in 2021, that lets websites push URL changes to search engines through a single HTTP request. Participating engines share the notifications with each other.

Does Google support IndexNow? No. Google uses its own Indexing API (limited to job posting and livestream pages) and sitemaps. Use IndexNow for Bing, Yandex, Naver, Seznam.cz and Yep, and keep your sitemap for Google.

How often can I submit the same URL? Submit a URL when its content changes. Resubmitting unchanged URLs repeatedly gives no benefit and may be ignored.

Can I submit URLs from a different domain? No. Every URL in a request must belong to the host the key is verified for. Use one IndexNowApi per site.

Is the key a secret? The key must be publicly readable at the key file URL, so it is not a secret in the usual sense. It only proves control of the host; rotate it if you suspect misuse.

Contributing

Issues and pull requests are welcome at github.com/uiuifree/rust-indexnow-api.

git clone https://github.com/uiuifree/rust-indexnow-api.git
cd rust-indexnow-api
cargo test --doc
cargo clippy

tests/ contains an integration test that sends a real request; run it only with a host and key you control.

License

MIT. See LICENSE.

Related resources