Find brands in a creator's videos
Sync a creator, then search each of their videos for your brands.
Zelf Detection finds brands in social videos. It reads the whole video and finds each scene where a brand is identifiable: its logo or name is visible (on a product, on packaging or in on-screen text) or the brand is named out loud. Every appearance comes back with its timestamp.
This guide starts from a creator's profile URL and ends with the brand placements in each of their videos. Sync the creator, list their videos, create one detection per video, then read the placements.
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.
Key concepts
- Creator sync
- Adds a creator's profile and posts to Zelf so their videos can be analyzed.
- Detection
- A search for a list of brands in one video. Detection is asynchronous: you create a detection, then poll it until it finishes.
- Placement
- One appearance of a brand in a video, with its timestamp.
- Identifiers
- Alternative names that count as the brand, such as product lines, characters and slogans.
- Negatives
- Terms that resemble the brand and should not count.
- 01Write the brand list
- 02Sync a creator
- 03Check the status of the sync
- 04List the creator's videos
- 05Create a detection
- 06Retrieve the results
- 07Read the placements
Write the brand list
List each brand to search for: a name, its identifiers and optional negatives. You send this list with the detection in step 5. Results depend on the list, so spend a few minutes on each brand.
identifiers2 to 10 | Names that count as the brand when they are visible on screen or spoken. Include the brand name, sub-brands, product lines, hero products, characters and slogans. Example for Nintendo: Nintendo, Switch, Mario, Pokemon, Zelda. Detection can miss a product or character that is not on the list, so use the 10 slots for the ones most likely to appear in videos. |
|---|---|
negativesup to 12 | Terms that look or sound like the brand but are not it, usually common words. Example for Nike: "Jordan (the country)", because "Jordan" is one of its identifiers. Example for Apple: "apple (the fruit)". |
namethe brand | The name the brand has in the results. See the limits in step 5. |
Sync a creator
Send the creator's profile URL to creator_sync.create. The sync adds the creator's profile and their own posts to Zelf. The response is the sync, {id, status, creator_id, profile_url, created_at, updated_at}. Use its id to check the status of the sync in the next step.
profile_urlone of these forms | https://www.instagram.com/<handle>, https://www.tiktok.com/@<handle> or https://www.youtube.com/@<handle>. |
|---|
pip install zelf-sdkimport os
from zelf import ZelfAPIClient
client = ZelfAPIClient(api_key=os.environ["ZELF_API_KEY"])
result = client.creator_sync.create(
profile_url="https://www.youtube.com/@milesandmornings",
)
print(result)Check the status of the sync
Syncing is asynchronous. Poll creator_sync.get with the sync id until status is SUCCESS or FAILED. The finished sync contains the creator_id. Use it to list the creator's videos in the next step.
SUCCESSfinal | The sync finished. creator_id is set. |
|---|---|
FAILEDfinal | The sync finished without a creator. |
pip install zelf-sdkimport os
from zelf import ZelfAPIClient
client = ZelfAPIClient(api_key=os.environ["ZELF_API_KEY"])
result = client.creator_sync.get("csj_3Yh7Nm5q")
print(result)List the creator's videos
Call content.list with the creator_id. Each video has an id (prefixed con_). Send each id to detection.create in the next step.
creator_idrequired here | The creator_id from the finished sync. |
|---|---|
content_formVIDEO | Detection does not accept photo posts. |
posted_after, posted_beforedate range | Include a date range. A single range covers up to 366 days. Request longer histories one range at a time. |
media_duration_maxoptional | Add media_duration_max=5400 to skip videos over 90 minutes. Detection does not accept them. |
page_sizepaging | 30 items per page. Follow next until it is null. |
pip install zelf-sdkimport os
from datetime import datetime, timezone
from zelf import ZelfAPIClient
client = ZelfAPIClient(api_key=os.environ["ZELF_API_KEY"])
result = client.content.list(
creator_id="cr_4Tz9Hs1k",
content_form="VIDEO",
posted_after=datetime(2026, 1, 1, tzinfo=timezone.utc),
posted_before=datetime(2026, 10, 1, tzinfo=timezone.utc),
media_duration_max=5400.0,
page_size=30,
)
print(result)Create a detection
Send a video id and your brand list to detection.create. The response contains the detection's id (prefixed aer_). Use that id to retrieve the results in the next step. Send one request per video.
Videolimit | One per request, up to 90 minutes long. YouTube, TikTok and Instagram videos (not photo posts). |
|---|---|
What countsscope | A brand counts when its logo or name is visible or the brand is named out loud. A product with no visible logo or name, and no spoken mention, is not detected. |
Video linklimit | When you send content_url instead of content_id: the full link to the video, not a short link (for example vm.tiktok.com). |
Brandslimit | Up to 200 per request. No two brand names that differ only by punctuation or digits (for example "Brand" and "Brand 2"). |
Identifierslimit | 2 to 10 per brand, each at least 2 characters. Include the brand name itself. |
Negativeslimit | Optional, up to 12 per brand. |
pip install zelf-sdkimport os
from zelf import ZelfAPIClient
client = ZelfAPIClient(api_key=os.environ["ZELF_API_KEY"])
result = client.detection.create(
content_id="con_8Qd2Vx7mLp",
context={
"hints": {
"brands": [{
"name": "Nike",
"identifiers": ["Nike", "Jordan", "Air Force 1"],
"negatives": ["Jordan (the country)"],
}, {
"name": "Netflix",
"identifiers": ["Netflix", "Stranger Things", "Squid Game"],
"negatives": [],
}, {
"name": "Starbucks",
"identifiers": ["Starbucks", "Frappuccino", "Pumpkin Spice Latte"],
"negatives": [],
}],
},
},
)
print(result)To run a different brand list on the same video, create a new detection.
Retrieve the results
Detection is asynchronous. Poll detection.get with the detection id until status is SUCCESS or FAILED. A finished detection lists each brand with its placements. For many videos, call detection.list (GET /api/v1/detection/) and follow next. It returns your detections, newest first, each with its status and, once finished, its result.
SUCCESSfinal | The detection finished. result lists each brand with its placements. |
|---|---|
FAILEDfinal | The detection finished without placements. result.brands is an empty list. |
pip install zelf-sdkimport os
from zelf import ZelfAPIClient
client = ZelfAPIClient(api_key=os.environ["ZELF_API_KEY"])
result = client.detection.get("aer_6Pz4Jb8n")
print(result)Read the placements
A finished detection has a result with three parts. video: {video_url, platform, duration_s}. summary: {brands_requested, brands_found, placements, confirmed, review}. brands: one entry per requested brand, in the order requested, each with its placements. A brand with found: false was searched for and does not appear in the video.
timestampplacement | A range (mm:ss-mm:ss) or a single moment (mm:ss). Past an hour the minutes keep counting, so 69:23 is an hour and nine minutes in. |
|---|---|
modalityplacement | Visual (logo or product on screen), Text (brand name written on screen) or Audio (brand name spoken). |
what_detected and reasoningplacement | What appears in the video, and why it counts as the brand. |
confidenceplacement | confirmed: the brand was visually confirmed in the video. review: detected, but not visually confirmed. Audio placements are always review, because a spoken mention has nothing visual to confirm. Use audio placements as they are. Check Visual and Text placements marked review before relying on them. |
video_url_at_timestampplacement | For YouTube, a link that opens the video just before the placement. Null on TikTok and Instagram. |
pip install zelf-sdkimport os
from zelf import ZelfAPIClient
client = ZelfAPIClient(api_key=os.environ["ZELF_API_KEY"])
result = client.detection.get("aer_6Pz4Jb8n")
print(result){
"id": "aer_6Pz4Jb8n",
"status": "SUCCESS",
"created_at": "2026-10-07T09:44:10Z",
"updated_at": "2026-10-07T09:52:38Z",
"context": {
"external_url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
"hints": { "brands": [{ "name": "Nike", "identifiers": ["Nike", "Jordan", "Air Force 1"], "negatives": ["Jordan (the country)"] }] }
},
"result": {
"video": {
"video_url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
"platform": "youtube",
"duration_s": 742
},
"summary": {
"brands_requested": 3,
"brands_found": 1,
"placements": 2,
"confirmed": 1,
"review": 1
},
"brands": [
{
"brand_name": "Nike",
"found": true,
"summary": { "placements": 2, "confirmed": 1, "review": 1 },
"placements": [
{
"timestamp": "01:12-01:19",
"video_url_at_timestamp": "https://www.youtube.com/watch?v=dQw4w9WgXcQ&t=67s",
"modality": "Visual",
"what_detected": "Nike swoosh on the right shoe during the lacing shot",
"reasoning": "The swoosh is unobstructed and fills most of the frame.",
"confidence": "confirmed"
},
{
"timestamp": "04:03",
"video_url_at_timestamp": "https://www.youtube.com/watch?v=dQw4w9WgXcQ&t=238s",
"modality": "Audio",
"what_detected": "Says \"these are the new Nikes\"",
"reasoning": "The brand is named directly in the voiceover.",
"confidence": "review"
}
]
},
{ "brand_name": "Netflix", "found": false, "summary": { "placements": 0, "confirmed": 0, "review": 0 }, "placements": [] },
{ "brand_name": "Starbucks", "found": false, "summary": { "placements": 0, "confirmed": 0, "review": 0 }, "placements": [] }
]
}
}Summary
| Step | Request | Input | Output |
|---|---|---|---|
| 1 | POST /api/v1/creator_sync/ | profile_url | sync id |
| 2 | GET /api/v1/creator_sync/{id}/ | sync id | creator_id |
| 3 | GET /api/v1/content/ | creator_id, date range, content_form=VIDEO | content ids (con_...) |
| 4 | POST /api/v1/detection/ | content_id and brand list | detection id (aer_...) |
| 5 | GET /api/v1/detection/ or /{id}/ | detection ids | status, result |
| 6 | read result | detection result | placements per brand |