Skip to navigation

Filtering and searching records

Use exact filters, semantic search, or both to find Records and provide context to Flows and Agents.

Filter records

A record filter selects Records of one type by their field values. A filter field names either a top-level Record field or a metadata key. The top-level fields are id, name, ownerId, createdAt, updatedAt, and schemaValid. Every other field name refers to a metadata key.

A field name is a single top-level key, and a filter does not read values inside nested objects. For example, a filter cannot select the city value inside an address object. To filter on a nested value, store it as its own top-level metadata key. Field names use letters, digits, underscores, periods, and hyphens, up to 64 characters. A field name can’t start with a period or a hyphen.

When you save a Record in the dashboard or with the Records API, Runtype stores its metadata keys in lowercase, with other characters replaced by underscores. For example, orderCount is stored as ordercount, and Order Count is stored as order_count. Use the stored key name in your filters.

Filter records in the dashboard

To filter the Records list, follow these steps:

  1. Go to Records.
  2. In the list view picker, select a Record type instead of All records. The filter builder appears only for a single Record type.
  3. Click Add filter.
  4. Choose a field, an operator, and a value. The list updates to show the matching Records.

The search box on the Records page matches Record names and types, not metadata values. Export and bulk edits use the active filter. For more information, see Search, filter, and export Records.

Write a record filter

In a Flow, set the recordFilter field of a List Records or Get Record step to a filter object. List Records returns the matching Records. Get Record returns the most recently updated matching Record. The filter requires a type field and can include a where clause with a condition or a group of conditions:

{
"type": "customers",
"where": {
"op": "and",
"conditions": [
{ "field": "tier", "op": "eq", "value": "premium" },
{ "field": "order_count", "op": "gt", "value": 10 }
]
}
}

Use "op": "and" or "op": "or" in a group to combine conditions. A group can contain one level of nested groups, and each group holds up to 50 conditions.

The type value and every string value in a condition accept {{variable}} templates. Runtype resolves them when the step runs, so a filter can match a value from the current run. Array items for in and notIn also accept templates.

List Records returns the most recently updated Records first. It returns up to 50 Records by default. Set limit to return up to 1000 Records.

The same filter object selects Records for bulk edits, for Schedule record targets, and for the Records API. For bulk edits, see Bulk edit Records.

Filter operators

The following table lists the operators that a condition accepts and the value each one requires:

OperatorValueExample
eq, neqA string, number, or Boolean. null is rejected.{ "field": "tier", "op": "eq", "value": "premium" }
gt, gte, lt, lteA number{ "field": "order_count", "op": "gte", "value": 5 }
betweenAn array of two numbers, [min, max]{ "field": "price", "op": "between", "value": [10, 50] }
contains, startsWith, endsWithA non-empty string{ "field": "email", "op": "endsWith", "value": "@example.com" }
in, notInA non-empty array of up to 200 values{ "field": "region", "op": "in", "value": ["us", "eu"] }
isSet, isNotSetNo value{ "field": "processed_at", "op": "isNotSet" }
isTrue, isFalseNo value{ "field": "active", "op": "isTrue" }
withinLastDays, olderThanDaysA number of days{ "field": "updatedAt", "op": "withinLastDays", "value": 7 }

contains, startsWith, and endsWith ignore letter case. eq is case-sensitive.

Comparison and range operators match JSON numbers and numeric strings such as 42 or 3.14. They do not match the top-level fields. The date-relative operators match ISO 8601 date and date-time strings, such as 2026-01-15T00:00:00.000Z. They also match the top-level createdAt and updatedAt fields. The filter does not match values in other formats.

Null and missing values

Value operators such as eq, gt, and contains do not match Records where the field is missing or set to JSON null. The neq and notIn operators also match Records where the field is missing or null. For example, a neq filter on a field that most Records do not have also returns those Records.

To select Records where a Boolean flag is not true, including Records that do not have the field, use { "field": "processed", "op": "neq", "value": true }. To filter only by field existence, use isSet or isNotSet.

Filter records with the API

GET /v1/records and GET /v1/records/export accept a record filter in the recordFilter query parameter. The value must be the filter JSON, base64-encoded. The following request lists premium customers:

FILTER='{"type":"customers","where":{"field":"tier","op":"eq","value":"premium"}}'
curl --get https://api.runtype.com/v1/records \
--header "Authorization: Bearer YOUR_API_KEY" \
--data-urlencode "recordFilter=$(printf '%s' "$FILTER" | base64 | tr -d '\n')"

Replace YOUR_API_KEY with your Runtype API key.

To check a filter before you use it, send the filter JSON as the body of POST /v1/records/preview-filter. The response includes the Record type, matchedCount, and up to 25 sample Records.

The following errors return HTTP status 400:

  • Invalid recordFilter: expected base64-encoded JSON: the parameter value does not decode to JSON.
  • Conflicting type: ?type=X but recordFilter.type=Y: the type query parameter and the filter’s type differ. Send one of them, or make them match.

Semantic search finds Records by meaning instead of exact keywords. Runtype converts your query into a vector embedding and returns the Records with the most similar embeddings.

Semantic search returns only Records that have an embedding. To add embeddings, use a Generate Embedding step and a Store Vector step in an ingest Flow. Use the same embedding model to index Records and to search them. With PostgreSQL (pgvector), the Vector Search step returns no results for Records that were embedded with a different model.

Queries such as these can match semantically related Records:

  • "How do I reset my password?" can match Records about password resets.
  • "Affordable laptops for students" can match Records about budget laptops.
  • "Shipping delays" can match shipping policies and updates.

Use semantic search for text-heavy fields such as descriptions, content, and article bodies. Use record filters for structured values such as IDs and numbers.

Search in a Flow

To add semantic search to a Flow, follow these steps:

  1. Add a Vector Search step.
  2. In the Search for field, enter the query text or a template such as {{userQuestion}}.
  3. In the in list, select the vector store.
  4. In the using field, select the embedding model that you used to index the Records.

The step card also sets the number of results and the minimum similarity score. A new step returns 5 results with a similarity of 0.7 or higher.

In a JSON step config, limit sets the number of results and defaults to 5. threshold sets the minimum similarity score from 0 to 1. If you omit threshold in JSON, the step applies no minimum. If you omit embeddingModel, the step uses text-embedding-3-small.

Search results

The step writes an array to its output variable, with the most similar Records first. For PostgreSQL (pgvector) and Cloudflare Vectorize, each item has these fields:

  • id: the Record or vector ID.
  • score and similarity: the same similarity score.
  • name and type: the Record name and type, for PostgreSQL (pgvector) results.
  • metadata: the Record metadata or the vector metadata.

The following sample shows one result:

[
{
"id": "record_01h2xcejqtf2nbrexx3vqjhp41",
"score": 0.82,
"similarity": 0.82,
"name": "Reset your password",
"type": "docs",
"metadata": { "content": "To reset your password, open Settings..." }
}
]

To read a field from the top result, use a template such as {{searchResults[0].metadata.content}}.

The Vector Search step can narrow a semantic search with recordType and metadataFilters. Support depends on the vector store, as the following table shows:

Vector storerecordTypemetadataFilters
PostgreSQL (pgvector)Returns only Records of that type. Omit it to search all types.Ignored
Cloudflare VectorizeMatches vectors whose type metadata equals the valueMatches each key exactly. Values must be strings, numbers, or Booleans.
WeaviateIgnoredApplies only the first key, as an exact match

Weaviate results have a different shape. Each item has id, score, rank, and properties fields instead of similarity and metadata.

In the dashboard, the filter by type field sets recordType for PostgreSQL (pgvector). To search for support articles about one product, set Search for to Technical issues with Widget Pro and filter by type to support.

Search examples

Customer lookup

The following List Records filter finds a customer by the email address in the current run:

{
"type": "customers",
"where": {
"op": "and",
"conditions": [{ "field": "email", "op": "eq", "value": "{{customerEmail}}" }]
}
}

The customerEmail flow variable supplies the email address, such as dana@example.com.

High-value customers

The following filter finds premium customers with a high lifetime value:

{
"type": "customers",
"where": {
"op": "and",
"conditions": [
{ "field": "lifetime_value", "op": "gt", "value": 10000 },
{ "field": "tier", "op": "eq", "value": "premium" }
]
}
}

The following Vector Search config searches docs Records:

{
"query": "{{userQuestion}}",
"recordType": "docs",
"limit": 3,
"outputVariable": "searchResults"
}

The userQuestion flow variable supplies the query text.

Product recommendations

The following Vector Search config returns products similar to a customer’s stated preferences:

{
"query": "{{userPreferences}}",
"recordType": "products",
"limit": 5,
"threshold": 0.7,
"outputVariable": "recommendations"
}

The userPreferences flow variable supplies the query text.

Next steps

Continue with these guides: