# Catch Algolia index drift before a campaign goes live

> A pre-launch review board that lines up every record in your Algolia index against the published Contentful entry, then fixes what drifted.

- Workflow type: app
- Services: Algolia, Contentful
- Categories: Operations, Marketing
- Published: 2026-08-14

## What it does

- Lists every record in a search index you choose, side by side with the published Contentful entry it came from.
- Sorts the problems into three worklists: records whose title, slug, or body no longer match the CMS, records missing values in the fields search actually looks at, and leftovers still sitting in search for content that was unpublished or deleted.
- Opens a field-by-field comparison when you click any row, so you can see exactly what changed before you touch anything.
- Repairs from the same screen: re-push the correct values from Contentful, refresh a whole record, or remove a leftover, one at a time or in bulk across a selected worklist.

## What you'll need

- An Algolia account, with an admin key so the app can repair records and not just read them
- A Contentful space with published content
- The name of the index your team wants to review before launch
- Index records that use the Contentful entry ID as their record ID, which is the usual convention when content is synced into search

## Prompt

Build me a search index health console: an app my content team opens before a campaign goes live to see where our Algolia index has drifted from Contentful, and to fix it on the spot. This is a weekly pre-launch review ritual a content ops person runs by hand, not a background job, so there is no schedule and no trigger. Everything happens because someone opened the app and clicked.

When the app opens, let me choose which index to review. Use Algolia List Indices to populate the picker, and remember my last choice. As soon as an index is selected, read its configuration with Algolia Get Settings and hold on to the searchable attributes. That list is what decides which attributes count as required later, so never hardcode a list of required fields. Show the searchable attributes somewhere visible in the header, because most people do not know what their index actually searches on, and the whole point is to explain what is missing rather than assume I already know.

To load a review, export the entire index with Algolia Browse Index. Browse is the correct read here because it uses a cursor and bypasses the 1000 hit search pagination cap, so keep calling it with the returned cursor until no cursor comes back and the whole index is in hand. In parallel, read the source of truth from Contentful with CDA - Get Published Entries, paging with skip and limit until you have every published entry. Match a record to an entry by treating the Algolia objectID as the Contentful entry sys.id, which is the convention our existing Contentful to Algolia sync already establishes. Compare against the default locale unless the user picks a different one.

Sort every record into three worklists, each its own tab with a count in the tab label. First, drifted records: the record exists and the entry is published, but the title, slug, or body no longer matches the published entry. Second, unfindable records: the record is missing a value, or has an empty value, in one or more of the attributes the index actually searches on, which silently makes it impossible to find even though it looks present. Name the specific empty attributes in the row, not just a generic warning. Third, orphans: records still sitting in the index whose entry is no longer published.

For orphans, tell the two causes apart, because the fix conversation differs. The published entries read alone cannot distinguish an unpublished entry from a deleted one, so for each orphan candidate check the management API with Contentful Get Entry (or Contentful List Entries for a batched lookup). If the entry still exists but has no published version, label it unpublished. If it is not found at all, label it deleted. Show that label on the row.

Clicking any row opens a detail view with a field-by-field diff of the index record against the Contentful entry, index value on the left and CMS value on the right, with changed, empty, and missing fields visually distinct. Re-read the single entry with Contentful CDA - Get Published Entry when the detail view opens so the diff reflects the current published state rather than a stale list read.

Let me repair from that same detail view. Re-push corrected fields from Contentful with Algolia Partial Update Record when only specific fields are wrong, or do a full refresh of the record from the entry with Algolia Add or Replace Record. For an orphan, let me remove it from the index with Algolia Delete Record. Every repair should say what it is about to do before it does it, since these are writes against production search.

Bulk work matters as much as single fixes. Let me multi-select rows in a worklist, including a select-all for the visible list, and re-push the whole selection in one action, choosing between a targeted field update and a full record refresh. For bulk orphan cleanup, Algolia Delete Records by Query is available when the selection can be expressed as a filter, otherwise fall back to deleting per record. Show per-row success and failure after a bulk run instead of a single summary toast, so a partial failure is obvious.

Keep a session counter in the header showing how many records were checked and how many were repaired in this sitting, and let me re-run the audit at any time to confirm a worklist is now clean. Two important behaviors to bake in: Algolia writes are asynchronous and return a taskID, so show repaired rows as pending until the change is confirmed rather than claiming instant success, and this app requires an Algolia Admin API key because a search-only key can read the index but cannot repair it. Say so clearly if writes are rejected for lack of permission. Contentful is read-only throughout: never write, publish, or unpublish anything in the CMS.

## How to customize

- Pick which index you review, and switch between staging and production indexes without any rebuild
- Change which fields must never be empty by editing the searchable fields in your index configuration, since the console reads that configuration instead of a hardcoded list
- Choose which fields count as drift, so the comparison matches your own content model rather than just title, slug, and body
- Decide whether a bulk fix updates only the changed fields or fully refreshes each record from the CMS

## FAQ

### Does this change anything in Contentful?

No. Contentful is treated as the source of truth and is only ever read. Every repair the app makes is written to your search index, so your content team's work in the CMS is never touched.

### Why would a page exist in search but still be impossible to find?

Search only matches on the fields you configured as searchable. If one of those fields is empty or missing on a record, the record is technically in the index but effectively invisible for those searches. That is exactly what the missing-values worklist catches, and it is the failure people usually notice only after a campaign is live.

### Will it handle a large index, or just the first page of results?

It reviews the whole index. The app exports every record rather than reading only the first page of search results, so a review covers the entire catalog instead of a sample.

### Do I need a developer to run the weekly review?

No. It is built for a content ops person: pick an index, look at the three worklists, click through the ones that matter, and fix them from the same screen.

### We already sync content into search automatically. Is this redundant?

No, it is the check on top of that sync. A one-way sync pushes new and updated content, but it usually misses deletes, unpublished pages, half-finished writes, and empty searchable fields. This app is the review surface that catches what the sync leaves behind.

### What if our records don't use Contentful entry IDs?

Matching relies on the record ID lining up with the Contentful entry ID, which is the standard convention for content synced into search. If your setup uses a different key, tell the builder which field holds the entry reference and it will match on that instead.

Use this prompt in General Input: https://www.generalinput.com/prompts/catch-algolia-index-drift-before-a-campaign-goes-live