Skip to main content
TEEI in Practice
Engineering note · Research & Engineering · 13 October 2026 How Algolia Powers Multilingual Search at TEEI

TEEI in Practice

Engineering noteResearch & Engineering

How Algolia Powers Multilingual Search at TEEI

With support from Algolia for Open Source, TEEI helps people find help answers and job titles in four languages, even when the spelling is imperfect.

On this page
  1. Key facts
  2. Where Algolia search runs today
  3. One index, four languages
  4. Combining Algolia’s retrieval with TEEI’s help-centre ranking
  5. One search, end to end
  6. Private by design
  7. Keeping search available with a fallback
  8. What we measured
  9. What we learned
  10. What comes next
  11. Thank you, Algolia
  12. Verify this
  13. Appendix: engineering notes
  14. Frequently asked questions
  15. Notes and sources

At TEEI, finding the right answer should not depend on perfect spelling or on knowing the official name of a job. With support from Algolia for Open Source,1 we use Algolia across our website and in TEEI Mentorship so that people can find help answers, blog posts and occupations with the words they actually use.

Search should work when someone is using a second language, typing on a phone or looking for help just before a call. They type “ukrane” when they mean Ukraine, or “sykeplier” when they mean sykepleier, the Norwegian word for nurse. They type “програміст” (programmer) in Ukrainian, or “не працює камера” (my camera is not working) a few minutes before a call. Algolia finds what they meant.

In the TEEI Mentorship job picker, that means searching 3,039 occupations in English, Norwegian, Polish and Ukrainian. In the TEEI Mentorship help centre, it means finding the answer about a camera or microphone from a search typed in Ukrainian. This article shows how those searches work, how we keep them private and what we measured on 13 October 2026. The engineering detail is in an appendix at the end.

Key facts

  • Algolia answers four search boxes: blog search and help on our website, the TEEI Mentorship help centre in English and Ukrainian, and the job picker in TEEI Mentorship.
  • The job picker searches 3,039 occupations in four languages. Before it went live, a fixed set of 83 test searches, typed the way people type them, all passed in development, staging and production.
  • Every search goes to Algolia from our own servers on Cloudflare, not from the reader’s browser. We send the words typed, any filters and the name of the box, never an account, an IP address or browser details.
  • Our own logs record which box was used, which engine answered, how many results came back and how long it took. Never the words.
  • We timed 150 live searches from Oslo on 13 October 2026, 50 to each of the three public boxes. The median time to an answer, our own servers included, was 77 ms on blog search, 69 ms on help and 201 ms in the TEEI Mentorship help centre. Algolia answered all 150.

Where Algolia search runs today

Table 1. The four search boxes Algolia answers, as of 13 October 2026.
Search boxWhereWhat it searches
Blog searchOur blogBlog posts
Help and FAQOur help pagesAnswers about taking part, volunteering and our programmes
TEEI Mentorship help centrementorship.theeducationalequalityinstitute.org/helpHelp answers for mentees and mentors, in English and Ukrainian
Job pickerThe TEEI Mentorship application and mentee goals, behind sign-inThe European list of 3,039 occupations (ESCO), in English, Norwegian, Polish and Ukrainian2

The website and the help centre share one index. It holds our blog posts and the help answers from our website, TEEI Language and TEEI Mentorship, in English, Norwegian, Polish and Ukrainian. One copy of each answer means the help centre and the website can never disagree about what it says. The job picker has an index of its own.

Two phones showing TEEI Mentorship in Ukrainian. On the left the job picker, where програміст lists software developer first. On the right the help centre, where не працює камера finds the answer about a camera or microphone that is not working. Both show the Search by Algolia logo.
Figure 1. Two of the boxes in Ukrainian. Left, the job picker: “програміст” puts the software developer first, above a CNC programmer. Right, the TEEI Mentorship help centre: “не працює камера” finds “My camera or microphone is not working”. Source: the TEEI Mentorship help centre in production, and the job picker on a test page that renders the same component and searches the same occupation list, captured 13 October 2026.

One index, four languages

The job picker is where Algolia matters most. A mentor or mentee applying to TEEI Mentorship chooses their job from ESCO, the European Union’s classification of occupations. The version we use lists 3,039 of them. We index each occupation once, with its names in English, Norwegian, Polish and Ukrainian. For common jobs we add our own names, where the official name is not what people type.

Algolia’s typo tolerance does much of the work without any setting: “sykeplier”, one letter short, still matches sykepleier. The settings decide which of the matches comes first. These are the index settings, unabridged:

js
export const SETTINGS = {
  searchableAttributes: [`${names('name')},${names('own')}`, names('alt')],
  indexLanguages: LANGUAGES,
  queryLanguages: LANGUAGES,
  ignorePlurals: true,
  decompoundedAttributes: { no: ['name_no', 'own_no', 'alt_no'] },
  attributesForFaceting: ['filterOnly(isco3)'],
  customRanking: ['desc(common)', 'asc(nameWords)'],
  attributesToRetrieve: ['code', 'isco3', ...LANGUAGES.map((lang) => `name_${lang}`)],
  attributesToHighlight: [],
  hitsPerPage: 6,
};
  • Official names and our own names rank level. The first entry puts ESCO’s preferred names and our own names at the same level in all four languages, and ESCO’s other names come after. We measured why on 10 October 2026. With our names one level lower, a Ukrainian “програміст” typed in full lost to a CNC programmer, whose official Ukrainian name happens to contain the word.
  • Algolia splits Norwegian compound words, so “sykepleier” also finds “spesialsykepleier”.3
  • Algolia’s custom ranking settles ties. When Algolia’s own criteria tie, a job with our own names ranks first, and a shorter name breaks the ties that remain.4 A misspelt “sykeplier” therefore puts the general nurse first, above the nine Norwegian compounds that also end in -sykepleier.
  • Plurals count as the same word in all four languages.
  • Only what the picker shows comes back: the occupation code, its job family and its four names, six results at a time.

For someone who trained as a nurse and is now looking for a mentor in Norway, this means the job they trained for comes first, even when the word comes out misspelt.

The TEEI Mentorship job picker with the misspelt Norwegian word sykeplier typed in. The first result is nurse responsible for general care, sykepleier, followed by other nursing jobs. The Search by Algolia logo is under the list.
Figure 2. The job picker with the misspelt Norwegian “sykeplier”. The general nurse comes first. Source: the TEEI Mentorship job picker on a test page that renders the same component and searches the same occupation list, because the picker itself sits behind sign-in, captured 13 October 2026.

Two checks stand in front of the live index. Before anything is written, the script that builds the index refuses a record over 10 KB. It also refuses any of our own names that does not match an ESCO occupation. And a fixed set of 83 searches, the words people type for common jobs in all four languages, runs against the index in each environment. A search passes when the right job comes first, or, for a word that fits several jobs equally, such as “teacher”, when it is among the six shown. Before the job picker went live, all 83 passed in development, staging and production.

Combining Algolia’s retrieval with TEEI’s help-centre ranking

The TEEI Mentorship help centre had its own ranking before it moved to Algolia: a word in an answer’s question counts most, then its keywords, then its text. We wanted to keep that order and add what Algolia does well, so each part got one job.

Algolia retrieves. It returns the answers that contain the reader’s words, misspellings and half-typed words included, in the reader’s language, as identifiers only. The help centre then orders them with the same ranker it uses on its own, and shows them from its own catalogue.

Algolia’s ranking can be tuned, and we could have tuned it to the same order. We chose one ranker for both paths instead, after a test on 8 October 2026 showed the two orders differing for “cancel session”. Readers get one stable order, while Algolia adds typo tolerance, prefix matching and multilingual retrieval.

One search, end to end

Diagram of one search. A reader's browser sends the words typed to the TEEI Worker on Cloudflare. The Worker asks Algolia with the query and filters only. If Algolia has not answered within 1.5 seconds, our own ranker answers instead. Either way the results, posts, help answers or jobs, go back to the page.
Figure 3. The path of one search. The blue path is the normal one; the dashed path is the fallback. Source: TEEI, drawn from the search code on our website, 13 October 2026.
  1. A reader types “ukrane” into blog search. Their browser sends the words to our Worker, the server code that runs on Cloudflare in the location nearest to them.
  2. The Worker sends Algolia the query, any filters and the name of the box, with a key that can only search. The reader’s IP address and account stay with our servers.
  3. Algolia answers with the matching posts, typo included: “ukrane” finds our Together for Ukraine posts.
  4. If Algolia has not answered within 1.5 seconds, or answers with an error, the Worker answers from the site’s own search instead.
  5. The page shows the results, and the Worker writes one log line: the box, the engine that answered, the number of results and the time taken.

The function that makes the call is in the appendix.

Private by design

  • Searches leave from our servers. Each search travels from our Worker to Algolia. We do not forward the reader’s IP address, account or browser details.
  • Algolia receives the words. A search is whatever the person typed, and Algolia needs it to answer. Algolia’s own request logs include the search itself, as its documentation describes.5
  • We never log what people type. Our log line holds the box, the engine, the number of results and the time taken. When Algolia does not answer, the line says why, and still not what was searched.
  • Every key opens one door. The servers hold keys that can only search. In TEEI Mentorship each environment has its own key, derived from a parent key and restricted to that environment’s indexes.6 We measured each one on 11 October 2026 before installing it. It searched its own index, and Algolia refused it on another environment’s index and on any write. A derived key that leaked would be revoked by replacing the parent key.
  • Only public text is indexed. Blog posts, help answers and the European occupation list. No person’s profile is in any index, and matching mentors with mentees never runs in Algolia.

Keeping search available with a fallback

If Algolia takes longer than 1.5 seconds or answers with an error, our own search answers from the same content, so the reader sees results either way. The website has one switch for its two boxes, and each box in TEEI Mentorship has its own, kept in the database so a box can change engine without a release. Blog search also works without JavaScript: the search page is an ordinary web form, and the search runs on the server either way.

What we measured

On 13 October 2026, at about 06:30 UTC, we sent 50 searches to each of the three public boxes from Oslo, 150 in all, one at a time and 150 ms apart. The job picker sits behind sign-in and was not timed. Each box got ten different searches, misspellings and Ukrainian included, five times each. Each time runs from sending the request to having read the answer, so it includes our own servers. Cloudflare answered from its Oslo location. Every answer says which engine produced it, and Algolia answered all 150.

Table 2. Time from request to answer for 50 live searches to each public box, 13 October 2026.
Search boxMedian95th percentileSlowestAnswered by Algolia
Blog search77 ms98 ms272 ms50 of 50
Help and FAQ69 ms82 ms90 ms50 of 50
TEEI Mentorship help centre201 ms376 ms470 ms50 of 50

The help centre does more per search than the website. It checks which programme and language the request belongs to, and asks Algolia for up to 200 candidate answers to rank itself. We have not measured how much of the extra time each of those steps takes.

Relevance is measured separately from speed. For the job picker, the 83 test searches described above all passed in development, staging and production. On the same day the website index held 844 records, 59 blog posts and 785 help answers, and the occupation index held 3,039.

What we learned

  • Give each engine one job. Algolia retrieves and the help centre’s ranker orders, so readers see one stable order and still get everything Algolia finds. Two engines that each ranked would have disagreed in front of a reader, as our test on 8 October 2026 showed.
  • Put everyday words level with the official ones. Official names are correct and often not what people type. One level of difference in the settings decided whether “програміст” found a programmer.
  • Make the fallback visible somewhere. The reader gets results either way, so an Algolia outage would never show on the page. The log line is the one place it shows: it names the engine that answered and, when that was not Algolia, the reason.
  • Prove each key before you install it. Search its own index, then try another environment’s index and a write, and expect a refusal on both.

What comes next

  • The TEEI Language help centre, once a release frees the space it needs (see the appendix).
  • Class search in the Skills Academy, the catalogue of live classes in TEEI Mentorship. It is built and switched off, and goes live with its release.

Thank you, Algolia

Through Algolia for Open Source, Algolia supports the search behind everything in this article. We are grateful for that support: it helps TEEI make programme information, help answers and occupation names easier to find for people who search in their second or third language.

The examples above show what that support looks like in practice: a misspelt Norwegian job title finding the general nurse, the Ukrainian word for programmer finding the software developer, and a Ukrainian question about a camera finding the right help answer. Thank you, Algolia, for supporting this work.

Verify this

Appendix: engineering notes

For developers who want the detail behind the sections above.

The function that makes the call

This is the function on our website that sends one search to Algolia. TEEI Mentorship sends the same request. One line is shown as a comment: the line that reads the answer and checks it against a schema.

ts
/** One search. Null means "answer from the site's own search": the reason is logged here. */
export async function algoliaSearch(
  config: AlgoliaConfig,
  params: AlgoliaQuery,
  fetcher: FetchLike = (input, init) => fetch(input, init),
  timeoutMs: number = ALGOLIA_TIMEOUT_MS,
): Promise<AlgoliaAnswer | null> {
  const { surface, ...search } = params;
  try {
    const res = await fetcher(algoliaQueryUrl(config), {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'X-Algolia-Application-Id': config.appId,
        'X-Algolia-API-Key': config.apiKey,
      },
      body: JSON.stringify({ ...search, analyticsTags: [surface] }),
      signal: AbortSignal.timeout(timeoutMs),
    });
    if (!res.ok) throw new Error(`status ${res.status}`);
    // One line here reads the answer and checks it against a schema (Answer).
    return { hits: answer.hits, nbHits: answer.nbHits };
  } catch (error) {
    console.warn(
      JSON.stringify({
        event: 'search.algolia_fallback',
        surface,
        reason: error instanceof Error ? error.message.slice(0, 120) : 'unknown',
      }),
    );
    return null;
  }
}

Three decisions are visible in it. It never throws. Missing configuration, a status other than 200, a timeout and a body that does not parse all return null, and null means “answer from our own search”. The time limit is a signal on the request itself, so a slow answer is abandoned rather than waited for. And the answer is checked against a schema before anything reads it, so a malformed body is one more failure rather than a crash further down. The box name travels as an Algolia analytics tag, so Algolia’s own dashboard can tell blog searches from help searches without us sending anything else.

Keeping the website index fresh

Diagram of the hourly refresh. A scheduled sync reads the search records from the deployed site. An error from the site stops it there. If the records changed, it writes records and settings into a copy of the index that nobody searches, then moves the copy over the live index in one operation. A run that does not report in on time raises an alert.
Figure 4. How the website index stays fresh. Source: TEEI, drawn from the sync job that writes the website index, 13 October 2026.
  • The records come from the deployed site. Every hour a scheduled job reads the search records from the live website, built by the same code its own search uses. The index can never hold a post or an answer the site would not show.
  • A broken source stops the job before Algolia is touched. If the website answers with an error, nothing is written, so a bad deploy cannot empty the index.
  • It writes only when something changed, judged by a fingerprint of the records and the settings. It also writes once a day anyway, so a change made by hand in Algolia’s dashboard does not last long.
  • The copy replaces the live index in one operation, so nobody ever searches a half-written index. The occupation index is written the same way.
  • A run that does not report in on time raises an alert.

Most hours, nothing has changed. A typical line from the production job’s log:

text
unchanged index=teei_site_prod blog=59 faq=785 sha=ac72c3a79d78

A platform limit

The TEEI Language help centre is not on Algolia yet. Its Worker already carries 128 settings and secrets, the most Cloudflare allows on one Worker on our plan.7 The three settings Algolia needs wait for a release that frees space.

Frequently asked questions

Does Algolia know who I am when I search?

We do not send Algolia your account, your IP address or details about your browser: the search goes to Algolia from our own servers, not from your browser. Algolia receives the words you type, because that is what it searches with, and its own request logs include them. Our own logs do not keep the words.

What happens if Algolia is slow or cannot be reached?

If Algolia has not answered within one and a half seconds, or answers with an error, our own search answers instead, so you still see results.

What is in the search indexes?

Public text only: our blog posts, the help answers from our website, TEEI Language and TEEI Mentorship, and the European list of occupations (ESCO) in four languages. No person's profile is indexed, and matching mentors with mentees never runs in Algolia.

Does blog search work without JavaScript?

Yes. The search page works as an ordinary web form, and the search runs on our server either way.

Why is there an Algolia logo under the search box?

Algolia supports TEEI through Algolia for Open Source, a programme for open and nonprofit projects. The Search by Algolia logo under the boxes Algolia answers credits that support, as the programme asks.

Notes and sources

  1. Algolia, Algolia for Open Source, read 13 October 2026. ↩

  2. ESCO, European Skills, Competences, Qualifications and Occupations, esco.ec.europa.eu, read 13 October 2026. Our index uses ESCO version 1.2.1. ↩

  3. Algolia documentation, decompoundedAttributes, read 13 October 2026. ↩

  4. Algolia documentation, Custom ranking, read 13 October 2026. ↩

  5. Algolia documentation, Get logs, read 13 October 2026. Each log entry includes the request body. ↩

  6. Algolia documentation, API key restrictions, read 13 October 2026. ↩

  7. Cloudflare documentation, Workers limits: environment variables, read 13 October 2026. ↩

More in Research & Engineering

Partnerships

Talk to us about building with TEEI

We use these details only to reply.