Playbook

Complicated searches

Operators, exact date windows, filters and sorting.

10 min 5 steps

The search box takes operators, so one request can cover several spellings of a brand and rule out the words that produce false matches.

Everything here stacks with the filters below it. The query narrows what matched, the filters narrow which posts come back, and order_by decides what you see first.

Every step shows the same call in all six Zelf clients and in cURL. Pick a language and the install line above the snippet switches with it. Each client reads your key from ZELF_API_KEY.

  1. 01Write the query
  2. 02Pick an exact window
  3. 03Narrow the result set
  4. 04Sort the results
  5. 05Collect a long history

Write the query

GET/api/v1/content/content.list

Operators are evaluated over the caption, transcript, summary and hashtags together. OR and NOT are case sensitive and have to be uppercase.

nike runningANDSeveral words mean all of them. This is the default.
nike OR adidasOREither term matches.
running NOT marathonNOTDrops posts that contain the second term.
"summer collection"phraseQuoted words match in that order, next to each other. NOT "out of stock" negates a phrase.
(nike OR adidas) runninggroupingParentheses group a clause before it is combined with the rest.
apple ONEAR/2 watchproximityBoth words within 2 words of each other, in that order. ONEAR binds more tightly than AND and OR.
pip install zelf-sdk
import os

from zelf import ZelfAPIClient

client = ZelfAPIClient(api_key=os.environ["ZELF_API_KEY"])

result = client.content.list(
    search="(nike OR \"air force 1\") running NOT marathon",
    posted_within_days=90,
)
print(result)

Pick an exact window

GET/api/v1/content/content.list

posted_within_days covers the common case. For a fixed period, send posted_after and posted_before as UTC timestamps. Use one or the other, not both styles at once.

posted_afterdate-timeISO 8601 UTC, for example 2026-01-01T00:00:00Z. Must not be in the future.
posted_beforedate-timeISO 8601 UTC. Sent on its own, the window starts 366 days before it.
posted_within_daysinteger1 to 365, counted back from now. The simpler form of the same thing.
pip install zelf-sdk
import os
from datetime import datetime, timezone

from zelf import ZelfAPIClient

client = ZelfAPIClient(api_key=os.environ["ZELF_API_KEY"])

result = client.content.list(
    search="running shoes",
    posted_after=datetime(2026, 1, 1, tzinfo=timezone.utc),
    posted_before=datetime(2026, 6, 30, 23, 59, 59, tzinfo=timezone.utc),
)
print(result)

A window wider than 366 days is refused with 400 VALIDATION_ERROR. Split a longer range into consecutive ranges and run one request per range.

Narrow the result set

GET/api/v1/content/content.list

Filters combine with AND. Every numeric filter has a _min and a _max form, and both bounds are inclusive.

platforminstagram, tiktokComma separated. Leave it out to cover every platform Zelf indexes.
content_formVIDEO, IMAGEUppercase. Detection only accepts VIDEO.
languagestringComma separated ISO 639-1 codes, for example en,es.
view_count_min, view_count_maxintegerSame pattern for like_count, comment_count, share_count and total_engagement.
engagement_rate_minfloatA fraction, not a percentage. 0.05 is five percent.
media_duration_min, media_duration_maxfloatSeconds. media_duration_max=5400 drops anything detection cannot take.
creator_follower_count_minintegerFilters on the creator behind the post rather than the post itself.
creator_usernamestringPartial, case insensitive. Also satisfies the scope rule on its own.
pip install zelf-sdk
import os

from zelf import ZelfAPIClient

client = ZelfAPIClient(api_key=os.environ["ZELF_API_KEY"])

result = client.content.list(
    search="running shoes",
    posted_within_days=90,
    platform=["instagram", "tiktok"],
    content_form="VIDEO",
    language=["en"],
    view_count_min=10000,
    engagement_rate_min=0.03,
    media_duration_max=5400.0,
)
print(result)

Sort the results

GET/api/v1/content/content.list

order_by takes a comma separated list. The direction is inverted compared with most APIs: a bare key sorts descending, and a minus prefix sorts ascending. The default is posted_at descending.

order_by=view_countdescendingMost viewed first. A bare key is always descending.
order_by=-posted_atascendingOldest first. The minus prefix flips to ascending.
order_by=view_count,-posted_atmultipleApplied left to right. Available keys: posted_at, view_count, like_count, comment_count, share_count, engagement_rate, total_engagement, earned_media_value_cents, net_promoter_score.
pip install zelf-sdk
import os

from zelf import ZelfAPIClient

client = ZelfAPIClient(api_key=os.environ["ZELF_API_KEY"])

result = client.content.list(
    search="running shoes",
    posted_within_days=90,
    order_by=["view_count"],
)
print(result)

net_promoter_score only sorts when the request is scoped with brand_id. Without it the request is refused with 400 BRAND_ID_REQUIRED.

Collect a long history

GET/api/v1/content/content.list

A single query reaches 3000 posts: 30 rows a page, 100 pages. To go past that, run the query once per date range and follow next within each one. Narrower ranges also keep each request fast.

pip install zelf-sdk
import os
from datetime import datetime, timezone

from zelf import ZelfAPIClient

client = ZelfAPIClient(api_key=os.environ["ZELF_API_KEY"])

result = client.content.list(
    search="running shoes",
    posted_after=datetime(2026, 7, 1, tzinfo=timezone.utc),
    posted_before=datetime(2026, 9, 30, 23, 59, 59, tzinfo=timezone.utc),
    page=1,
)
print(result)

Over the limit you get 429 RATE_LIMIT_EXCEEDED with error.details.retry_after_seconds and the scopes that blocked. Wait that long and continue. Failed requests do not count against your quota.