Skip to main content

Search-only API keys on web

Inside your app you can use the search-only API key. You can include this key directly in your frontend code. It might happen that you need to apply some rate limiting to your API Key. For those cases, you can generate secured API keys.

Secured API keys

Secured API Keys are useful when you want to restrict the search to a set of indices, for example. Those keys need to be generated on the backend. Otherwise, users can modify the restrictions of the key by modifying the frontend code. This guide doesn’t focus on how to use Secured API Keys, but rather on the usage of those keys in an InstantSearch app. The aim is to implement an app that generates a secured API key on the server, then uses it on the client. The secured API Key will have a restriction on the index. You can find the complete example on GitHub.

Server

Generate the secured API key

To restrict access to a specific index and set of search operations, you must generate a 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. Usually, this parent key is your search-only API key. In this example, the generated key is restricted to the demo_ecommerce index. This means the frontend can’t query other indices using this key. You can apply additional restrictions, including search parameters to fine-tune access.
JavaScript
const algoliasearch = require("algoliasearch");

const client = algoliasearch("ALGOLIA_APPLICATION_ID", "ALGOLIA_SEARCH_API_KEY");
const securedApiKey = client.generateSecuredApiKey("ALGOLIA_SEARCH_API_KEY", {
  restrictIndices: "demo_ecommerce",
});
Once you have the key, you must pass it to the client with one of two implementations:
  • Create an endpoint on your server that will send back the API Key. Then on the client before creating the app you need to asynchronously fetch the API key from the server.
  • Inline the API key in the HTML. Then, on the client, you can directly create the app by reading the value from the global object.
This guide uses the second option: inline the API key.

Inline the API key

For simplicity, this example uses Parcel. In Parcel, you don’t create the HTML file from scratch but use the one generated by the CLI. To inject data from the server, use a placeholder value in the HTML. Note that this step is only useful if you are using an app generated from a CLI. Otherwise you can directly inline the value inside your HTML template.
HTML
<!DOCTYPE html>
<html lang="en">
  <head>
    <script>
      window.SERVER_DATA = __SERVER_DATA__;
    </script>
  </head>
</html>
Once the placeholder is set up, it can be replaced 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);
});
That’s it for the server. You should now be able to run the server and access your generated API key from the client with window.SERVER_DATA. The next section of this guide describes 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 index demo_ecommerce. 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>
        `;
      },
    },
  })
]);