Skip to main content

Search-only API keys in web apps

You can use the search-only API key in your frontend code. This key is safe to expose because it only allows search operations. If you need additional restrictions, such as limiting the access to specific indices, or applying rate limits, generate a secured API key on your backend.

Secured API keys

Secured API keys add restrictions and search parameters that your users can’t change. You must generate them on your server, or anyone can remove the restrictions again. This guide shows how to use secured API keys in an InstantSearch app. For mode details, see User-restricted access to data. The aim is to build an app that generates a secured API key with restrictions on the server, and then uses it on the client. See the full example on GitHub.

Server

Generate a secured API key

Generate the secured API key on your server. This example uses Express, but the same approach works with any server. To generate a key, you need the Algolia JavaScript client and a parent API key with the search ACL. In this example, the generated key only allows searching the demo_ecommerce index. You can also apply additional restrictions, including search parameters.
JavaScript
const algoliasearch = require("algoliasearch");

const client = algoliasearch("ALGOLIA_APPLICATION_ID", "ALGOLIA_SEARCH_API_KEY");
const securedApiKey = client.generateSecuredApiKey({
  parentApiKey: "ALGOLIA_SEARCH_API_KEY",
  restrictions: {
    restrictIndices: "demo_ecommerce",
  },
});
Send the secured API key to the client in one of these ways:
  • Return it from an endpoint, then fetch it before you create your InstantSearch app.
  • Inline it in the HTML, then read it from a global object in the client.
This example inlines the key.

Inline the API key

If your build tool generates the HTML, add a placeholder value and replace it on the server before sending the page.
If you control the HTML template, inline the value directly.
HTML
<!DOCTYPE html>
<html lang="en">
  <head>
    <script>
      window.SERVER_DATA = __SERVER_DATA__;
    </script>
  </head>
</html>
Replace the placeholder with the generated API key:
JavaScript
const path = require("path");
const fs = require("fs");
const util = require("util");
const express = require("express");

const app = express();
const readFileAsync = util.promisify(fs.readFile);

app.get("/", async (_, res) => {
  const index = await readFileAsync(
    path.join(__dirname, "dist", "index.html"),
    "utf-8",
  );

  const indexWithServerData = index.replace(
    "__SERVER_DATA__",
    JSON.stringify({
      ALGOLIA_API_KEY: securedApiKey,
    }),
  );

  res.send(indexWithServerData);
});
Start the server and read the key from window.SERVER_DATA in the client. The next section explains how to use this key in an InstantSearch app.

Client

Retrieve the API key

Now that you have the API key on the global object, you can retrieve it from the client code and inject it into searchClient. Make sure you clean up the global object. Otherwise, this value will stay in memory.
JavaScript
const SERVER_DATA = window.SERVER_DATA;

// clean up the global object
delete window.SERVER_DATA;

const searchClient = algoliasearch(
  "ALGOLIA_APPLICATION_ID",
  SERVER_DATA.ALGOLIA_API_KEY,
);

const search = instantsearch({
  indexName: "demo_ecommerce",
  searchClient,
});
That’s it for the client. Your app can now only target the demo_ecommerce index. You can try to target a different one like demo_media but the API will return an error.

Prevent cross-site scripting vulnerabilities

Algolia’s highlighting feature helps users understand how their query matches the results. It’s a key visual cue. Algolia’s highlighting feature helps users understand how their query matches the results. It’s a key visual cue. Algolia wraps matching words in HTML tags. By default, it uses tags like em, which the browser renders as HTML. If your site includes user-generated content, this can expose your app to cross-site scripting (XSS) attacks. The same risk applies to the snippeting feature. To prevent this, InstantSearch restricts highlighting to a predefined set of HTML tags and escapes all others. If you set a custom tag in the Algolia dashboard, it’s overridden and replaced by mark. To use a different tag, such as strong, set the highlightedTagName props in Highlight or Snippet.
All examples in this guide assume you’ve included InstantSearch.js in your web page from a CDN. If, instead, you’re using it with a package manager, adjust how you import InstantSearch.js and its widgets.

Usage with template functions

You can also provide the argument to the Highlight and Snippet components from template functions.
JavaScript
const search = instantsearch({
  indexName: 'instant_search'
  searchClient,
});

search.addWidgets([
  instantsearch.widgets.hits({
    container: '#hits',
    templates: {
      item(hit, { html, components }) {
        return html`
          <article>
            <h2>${components.Highlight({ hit, attribute: 'name' })}</h2>
            <p>${components.Snippet({ hit, attribute: 'description' })}</p>
          </article>
        `;
      },
    },
  })
]);
Last modified on March 2, 2026