Skip to Content
FeaturesAI & Search

AI & Search

Foir includes built-in semantic search that lets you find content by meaning rather than exact keywords. No external machine learning infrastructure required.

Overview

Traditional search matches keywords. Semantic search understands meaning. When a user searches for “affordable running shoes,” semantic search also finds content about “budget sneakers for jogging” — even if none of those exact words appear.

Foir automatically generates vector embeddings for your content and stores them alongside your records. You query with natural language, and the platform returns the most relevant results ranked by similarity.

How Embeddings Work

Embeddings are the foundation of semantic search. Here is the high-level flow:

Your Content Vector Space +-----------------------+ +-----------------------+ | "Lightweight | | | | running shoes | --> | [0.12, -0.34, | | for beginners" | Embed | 0.87, ...] | +-----------------------+ +-----------------------+ User Query Similarity Match +-----------------------+ +-----------------------+ | "beginner | | Score: 0.91 | | jogging gear" | --> | -> running shoes | | |Search | Score: 0.85 | +-----------------------+ | -> starter kit | +-----------------------+
  1. Embedding generation — When you create or update a record, Foir extracts text from configured fields and converts it into a numerical vector.
  2. Storage — The vector is stored alongside the record, scoped to your project.
  3. Search — When a query comes in, it is converted to a vector and compared against stored vectors using cosine similarity.
  4. Results — Records are ranked by how closely their meaning matches the query.

Content Sources

Semantic search works with two types of content:

SourceDescriptionExample
EntityVersioned content with publishing workflowsPages, blog posts, product descriptions
DataFlat records with direct CRUD accessFAQ entries, support articles, knowledge base items

You can search across both sources simultaneously or filter to one type.

In the Admin

Enabling Embeddings on a Model

  1. Navigate to Settings > Models
  2. Select the model you want to enable for semantic search
  3. Under Capabilities, toggle Embeddings on
  4. Choose which fields to include in the embedding (text fields, rich text, etc.)
  5. Save the model

Once enabled, Foir generates embeddings for existing records in the background and automatically embeds new or updated records going forward.

Searching in the Admin

The admin dashboard includes a global search bar that uses semantic search when enabled:

  1. Click the Search icon or press /
  2. Type a natural language query
  3. Results are ranked by relevance across all embedding-enabled models
  4. Click a result to navigate directly to the record

Via the CLI

Searching

# Semantic search across all models foir search "lightweight running shoes" --limit 10 # Search specific models foir search "return policy for damaged items" --models faq,support-article --limit 5

Managing Embeddings

# Write an embedding for a record (input payload describes the record and vector) foir embeddings write --file ./embedding.json # Delete the embedding for a specific record foir embeddings delete rec_abc123 --confirm # Search by vector similarity foir embeddings search --data '{"query": "beginner jogging gear", "modelKeys": ["product"], "limit": 5}' # List embeddings stored for a record foir embeddings list rec_abc123 # Stats for a specific model foir embeddings stats product --json # Project-wide embedding stats (no model key) foir embeddings stats --json # Find records similar to a given one foir embeddings similar rec_abc123 --model-key product --limit 5

See foir embeddings for the full subcommand and option reference.

Via the API

semanticSearch Query

Search your content by meaning using vector similarity. Returns records ranked by how closely they match your query.

Required scope: search:read

query SearchProducts { semanticSearch(input: { query: "lightweight shoes for trail running" modelKeys: ["product"] source: RECORD limit: 10 threshold: 0.7 }) { recordId source modelKey naturalKey similarity highlights } }

Input Fields

FieldTypeRequiredDescription
queryStringYesNatural language search query
modelKeys[String]NoFilter by specific model keys
sourceEmbeddingSourceNoRECORD — currently the only source type
limitIntNoMaximum results to return (default: 10)
thresholdFloatNoMinimum similarity score 0-1 (default: 0.0)

Response Fields

FieldTypeDescription
recordIdIDThe matching record’s ID
sourceEmbeddingSourceAlways RECORD
modelKeyStringThe model key of the matching record
naturalKeyStringThe record’s natural key (slug, handle, etc.)
similarityFloatSimilarity score from 0 to 1 (higher = more similar)
highlights[String]Relevant text excerpts from the matching content

Search Across All Content

query GlobalSearch { semanticSearch(input: { query: "how to set up two-factor authentication" limit: 5 threshold: 0.6 }) { recordId modelKey naturalKey similarity } }

embeddingStatus Query

Check whether specific records have embeddings generated.

Required scope: search:read

query CheckEmbeddings { embeddingStatus( recordIds: ["rec_abc123", "rec_def456"] source: RECORD ) { recordId hasEmbedding model dimensions lastUpdated } }
FieldTypeDescription
recordIdIDThe record ID
hasEmbeddingBooleanWhether an embedding exists
modelStringEmbedding model used (e.g., text-embedding-3-small)
dimensionsIntVector dimensions
lastUpdatedDateTimeWhen the embedding was last generated

generateEmbedding Mutation

Manually generate an embedding for a specific record. Useful when you need a record to be immediately searchable after creation.

Required scope: records:write

mutation EmbedRecord { generateEmbedding( recordId: "rec_abc123" modelKey: "product" source: RECORD ) { success embeddingId recordId tokenCount dimensions skipReason } }
FieldTypeDescription
successBooleanWhether embedding was generated
embeddingIdIDThe generated embedding ID
recordIdIDThe record ID
tokenCountIntTokens used for embedding
dimensionsIntVector dimensions
skipReasonStringWhy embedding was skipped (e.g., content unchanged)

If the content has not changed since the last embedding, the operation is skipped automatically and skipReason indicates why.

Error Handling

CodeDescription
FORBIDDENAPI key lacks required scope
AI_DISABLEDSearch features not enabled for project
NOT_FOUNDRecord or model not found
VALIDATION_ERRORInvalid input parameters

Best Practices

  • Set a similarity threshold to filter out low-quality matches. A threshold of 0.6-0.7 works well for most use cases.
  • Choose embedding fields carefully — include the fields that best describe your content (titles, descriptions, body text) and exclude metadata fields.
  • Use modelKeys filtering when you know which content types are relevant to narrow results and improve relevance.
  • Re-generate embeddings after significant content updates using foir embeddings write or the generateEmbedding mutation.

Use Cases

  • E-commerce product discovery — Let customers describe what they are looking for in natural language instead of navigating category trees.
  • Help center / FAQ search — Feed support articles into the search index and let users find answers by asking questions in plain English.
  • Content recommendations — Find similar articles, products, or pages based on meaning rather than tags using foir embeddings similar.
  • Internal search — Build a search experience across all your project content that understands intent, not just keywords.
Last updated on