How do I search TikTok and YouTube by what happens in a video?
Search an index of moments instead of each app. UpRock's video_search takes a plain description, like "snorkeling with sea turtles", and returns up to ten short moments from public YouTube, TikTok and Instagram video, each with its start and end time and a link back to the original, so you land on the part that matches instead of the start of an hour-long video. It costs $1 per 1,000 searches.
Updated · Read as markdown
What a moment search returns
The thing you're looking for is often 30 seconds in the middle of a long video, and nobody says it out loud. A moment index cuts each video into short windows and keeps notes on each one: what's said, a model-written description of what happens, and the timestamps. A search compares your words with those notes by meaning and returns the windows, not just the video. The index holds notes on public videos, not copies of them, and every result points back to the original post.
UpRock's video_search tool, on the MCP server at https://mcp.uprock.ai/mcp, with your API key in an Authorization: Bearer header (clients that can't send headers can use https://mcp.uprock.ai/<API_KEY>/mcp instead), returns up to 10 results, best first. Each result has:
| Field | What it is |
|---|---|
url | The original post on YouTube, TikTok or Instagram |
t0, t1 | Start and end of the moment, in seconds from the start of the video |
score | How well the moment matches, for ranking within one search |
title | The post's title as indexed (Instagram posts show "Video by" and the account name) |
transcript | An excerpt of what's said in the moment; empty when nobody speaks |
source | The platform: youtube, tiktok or instagram |
published_at | When the video was published, in unix seconds |
Moments are windows of up to 30 seconds on a 25-second grid: every t0 we saw was a multiple of 25. Three options shape the results. unique_videos (on by default) keeps only the best moment from each video, published_after and published_before (unix seconds) limit the publish dates, and order_by_recency sorts newest first, with relevance as the tiebreak.
Five searches we ran on 25 Oct 2026
We ran each query once with the default settings and copied the top three results. Titles are trimmed, and each links to the moment; YouTube links start at the second.
"walking through a night market with street food"
| Platform | Moment | Score | Title |
|---|---|---|---|
| YouTube | 10:00 to 10:30 | 0.708 | First Time Trying Turkey's Famous Wet Burger in Taksim Square |
| 0:00 to 0:30 | 0.704 | Video by lonelyplanet | |
| YouTube | 50:00 to 50:30 | 0.687 | Istanbul Street Food!! ULTIMATE TURKISH FOOD You Must-Try in Istanbul |
The top ten held five YouTube moments, four Instagram and one TikTok. Two of these three sit 10 and 50 minutes into long food tours, and the first is narrated in Urdu.
"snorkeling with sea turtles"
| Platform | Moment | Score | Title |
|---|---|---|---|
| YouTube | 7:05 to 7:35 | 0.749 | $1 vs $1,000,000 Vacation! |
| YouTube | 48:20 to 48:50 | 0.631 | Morning News NOW Full Episode, June 17 |
| 0:00 to 0:24 | 0.609 | Video by visitjapanau |
Five YouTube and five Instagram moments. The second hit is a 30-second window 48 minutes into a full news episode, and neither of the two YouTube transcripts mentions turtles.
"a cable car going up a mountain"
| Platform | Moment | Score | Title |
|---|---|---|---|
| YouTube | 8:45 to 9:15 | 0.712 | Salzburg Vacation Travel Guide |
| 0:00 to 0:27 | 0.702 | Video by switzerland | |
| 0:25 to 0:55 | 0.693 | Video by karaandnate |
Eight Instagram moments and two YouTube. In the travel guide, the matching moment comes almost nine minutes in.
"slicing a watermelon"
| Platform | Moment | Score | Title |
|---|---|---|---|
| YouTube | 1:15 to 1:45 | 0.712 | Skin a Watermelon Party Trick |
| YouTube | 0:50 to 1:20 | 0.672 | Simple Watermelon Smoothie Hack |
| YouTube | 3:45 to 4:15 | 0.665 | Nastya and new friendly family stories for children and their parents |
Eight YouTube moments and two TikTok, the first at number five. The third result is a near miss: a children's story in which a character has been turned into a watermelon. The words matched; the action didn't.
"changing a bike tire"
| Platform | Moment | Score | Title |
|---|---|---|---|
| YouTube | 0:50 to 1:20 | 0.625 | Man bikes from Pittsburgh to Dallas to watch his home team's World Cup match |
| TikTok | 0:25 to 0:55 | 0.618 | the gremlins wanted a bike |
| YouTube | 2:55 to 3:25 | 0.570 | I Built 4 SECRET Rooms In ONE COLOR! |
Judging by titles and transcripts, none of the top ten shows a tire being changed. A search only finds what has been indexed, and so far the index leans toward travel and food. How-to queries are worth a try, but check what comes back.
Linking to the exact second
t0 is the second to send people to. How you link to it depends on the platform:
| Platform | Link starts at a second? | How |
|---|---|---|
| YouTube | Yes | Add t= with the second, for example https://www.youtube.com/watch?v=Q6vVuj3iggE&t=75s. YouTube's Share dialog does the same when you tick "Start at", and embedded players take start and end in seconds |
| TikTok | No documented parameter | Link to the post and print the time next to it |
| No documented parameter | Link to the post and print the time next to it |
We couldn't find a start-time parameter in TikTok's or Instagram's documentation when we checked on 25 Oct 2026. It matters less than it sounds: of the 194 TikTok and Instagram moments in our 28 searches, 115 started at 0:00 and 180 in the first minute.
Searching from code
Both versions call video_search over MCP, pass the filters, and print each moment with a link to it. Give them a query, and optionally a date to get only videos published since then, newest first.
// npm i @modelcontextprotocol/sdk (Node 24+ runs .ts files directly) env: UPROCK_API_KEY// node moments.ts "snorkeling with sea turtles" best moment per video// node moments.ts "snorkeling with sea turtles" 2026-01-01 published since then, newest firstimport { Client } from "@modelcontextprotocol/sdk/client/index.js";import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";// One video_search result: a moment from t0 to t1 (seconds) in one public video.type Moment = { url: string; t0: number; t1: number; score: number; title: string; transcript: string; source: string; // "youtube", "tiktok" or "instagram" published_at: number; // unix seconds};type SearchOptions = { since?: Date; // published_after newestFirst?: boolean; // order_by_recency everyMoment?: boolean; // unique_videos: false returns several moments per video};const uprock = new Client({ name: "video-moments", version: "1.0.0" });await uprock.connect( new StreamableHTTPClientTransport( new URL("https://mcp.uprock.ai/mcp"), { requestInit: { headers: { Authorization: `Bearer ${process.env.UPROCK_API_KEY}` } } }, ),);export async function searchMoments(query: string, opts: SearchOptions = {}) { const args: Record<string, unknown> = { query, unique_videos: !opts.everyMoment, order_by_recency: opts.newestFirst ?? false, }; if (opts.since) args.published_after = Math.floor(opts.since.getTime() / 1000); const res = await uprock.callTool({ name: "video_search", arguments: args }); const text = (res.content as { type: string; text?: string }[]).find((c) => c.type === "text") ?.text ?? ""; if (res.isError) throw new Error(`UpRock: ${text}`); return (JSON.parse(text).results ?? []) as Moment[];}// YouTube links can start at a second. TikTok and Instagram document no such// parameter, so their links open the post and the time is printed next to them.export function linkToMoment(m: Moment) { const url = new URL(m.url); if (/(^|\.)youtube\.com$|^youtu\.be$/.test(url.hostname)) { url.searchParams.set("t", `${Math.floor(m.t0)}s`); } return url.toString();}function clock(seconds: number) { const s = Math.floor(seconds); const [h, m, sec] = [Math.floor(s / 3600), Math.floor((s % 3600) / 60), s % 60]; const mmss = `${h ? String(m).padStart(2, "0") : m}:${String(sec).padStart(2, "0")}`; return h ? `${h}:${mmss}` : mmss;}const [query = "snorkeling with sea turtles", since] = process.argv.slice(2);try { const moments = await searchMoments( query, since ? { since: new Date(since), newestFirst: true } : {}, ); for (const m of moments) { const when = `${clock(m.t0)}-${clock(m.t1)}`; console.log( `${m.score.toFixed(3)} ${m.source.padEnd(9)} ${when.padEnd(13)} ${m.title.slice(0, 50)}`, ); console.log(` ${linkToMoment(m)}`); }} finally { await uprock.close();}# pip install "mcp>=2.3" env: UPROCK_API_KEY# python moments.py "snorkeling with sea turtles" best moment per video# python moments.py "snorkeling with sea turtles" 2026-01-01 published since then, newest firstimport asyncioimport calendarimport jsonimport osimport sysfrom datetime import datefrom urllib.parse import parse_qsl, urlencode, urlsplit, urlunsplitimport httpx2from mcp import Clientfrom mcp.client.streamable_http import streamable_http_client# The key goes in an Authorization header, set on the HTTP client the MCP client uses.UPROCK = "https://mcp.uprock.ai/mcp"HEADERS = {"Authorization": f"Bearer {os.environ['UPROCK_API_KEY']}"}YOUTUBE = {"youtube.com", "www.youtube.com", "m.youtube.com", "youtu.be"}async def search_moments( client: Client, query: str, since: date | None = None, newest_first: bool = False, every_moment: bool = False,) -> list[dict]: args = { "query": query, "unique_videos": not every_moment, # False: several moments per video "order_by_recency": newest_first, } if since: args["published_after"] = calendar.timegm(since.timetuple()) # midnight UTC res = await client.call_tool("video_search", args) text = next((c.text for c in res.content if c.type == "text"), "") if res.is_error: raise RuntimeError(f"UpRock: {text}") return json.loads(text).get("results", [])def link_to_moment(m: dict) -> str: """YouTube links can start at a second; TikTok and Instagram document no such parameter, so their links open the post and the time is printed next to them.""" parts = urlsplit(m["url"]) if parts.hostname in YOUTUBE: params = dict(parse_qsl(parts.query)) | {"t": f"{int(m['t0'])}s"} parts = parts._replace(query=urlencode(params)) return urlunsplit(parts)def clock(seconds: float) -> str: h, rest = divmod(int(seconds), 3600) m, s = divmod(rest, 60) return f"{h}:{m:02}:{s:02}" if h else f"{m}:{s:02}"async def main() -> None: query = sys.argv[1] if len(sys.argv) > 1 else "snorkeling with sea turtles" since = date.fromisoformat(sys.argv[2]) if len(sys.argv) > 2 else None async with ( httpx2.AsyncClient(headers=HEADERS, timeout=httpx2.Timeout(30, read=300)) as http, Client(streamable_http_client(UPROCK, http_client=http)) as client, ): moments = await search_moments(client, query, since, newest_first=bool(since)) for m in moments: when = f"{clock(m['t0'])}-{clock(m['t1'])}" print(f"{m['score']:.3f} {m['source']:<9} {when:<13} {m['title'][:50]}") print(f" {link_to_moment(m)}")asyncio.run(main())Speed, filters and cost
- Speed. Searches with the default settings took 4.2 to 5.4 seconds (median 4.6) across 29 runs on 25 Oct 2026. With
unique_videosoff they took about 2.1 seconds and returned several moments from the same video, and a slightly different set: the night-market search lost its YouTube top hit. - Newest first.
order_by_recencysorts by publish date before relevance, so pair it withpublished_after. For "a cable car going up a mountain" since 1 Jan 2026, newest first, the top result was a news clip scoring 0.416; sorted by relevance, the same search led with a 0.694 match. - Cost. $1 per 1,000 searches by card or USDC, $0.80 with UPT, prepaid. There's nothing to store and no plan.
Tested 25 Oct 2026 against the live UpRock MCP server: we extracted both code blocks from this page and ran them with "snorkeling with sea turtles", with and without a date (Node 25 with @modelcontextprotocol/sdk 1.32.2, Python 3.11 with mcp 2.3.0). Both printed ten moments, with YouTube links that start at the moment. We didn't open the links in a browser, so the start-time behavior follows YouTube's documentation. On 6 Nov 2026 we ran both code blocks again with an UpRock API key in an Authorization header, with and without a date.
FAQ
Does this search every video on YouTube, TikTok and Instagram?
No. It searches the public videos that have been indexed so far. In our 28 test searches on 25 Oct 2026, results came from YouTube, TikTok and Instagram; travel and food queries matched best, and a how-to query like "changing a bike tire" returned nothing on topic.
Does UpRock keep copies of the videos?
No. The index holds notes on each video, such as transcripts, model-written descriptions of what happens and timestamps. Every result links to the original post, so people watch it where it was published.
Can I link to the exact second on TikTok or Instagram?
We couldn't find a documented start-time parameter for either (checked 25 Oct 2026), so link to the post and show the time next to it. Most of their moments in our searches started in the first minute anyway. YouTube documents one; add t= with the second.
What do t0, t1 and score mean?
t0 and t1 are the start and end of the moment in seconds from the start of the video. Moments are windows of up to 30 seconds on a 25-second grid. The score ranks results within one search and isn't a probability. On-topic top results scored about 0.6 to 0.75 in our runs, but an off-topic one scored 0.625.
What does a search cost?
$1 per 1,000 searches by card or USDC, $0.80 with UPT, prepaid. Each search returns up to ten moments, and the filters don't change the price.
Other use cases to explore
- See where a transcript search would miss: three searches whose best moments had no transcript, a speech-recognition artifact or speech in another language.
- Give Claude Code video search: add UpRock's MCP server once and ask for the moment in a video from your terminal.
- See a page as it looks in another country: load a URL on a real device in the country you choose.
- The open video index: how the shared index works, what's in it and what searching and indexing cost.
References
- UpRock, everything in one file (MCP server, tools and prices), checked 25 Oct 2026
- UpRock, the open video index, checked 25 Oct 2026
- YouTube Help, Share videos and channels ("Start at"), checked 25 Oct 2026
- YouTube IFrame Player API, player parameters (start and end), checked 25 Oct 2026
Get started
Add UpRock in one paste.
Paste this into Claude Code, Codex, Cursor or any agent with a terminal. It reads our docs, sets up the MCP server or CLI, and tells you the cost before it spends anything.
Set up UpRock for me: read https://uprock.ai/agents.md, connect the UpRock MCP server, and run one test crawl. Tell me what it costs before you spend anything.