Local-First YouTube Transcript Extension: What It Can See
A Chrome extension with host permission for youtube.com can read the video page you have open, call YouTube's caption endpoint with your own cookies, and read that tab's URL and title. Host permission for youtube.com alone gives it nothing on any other site. The install dialog says this in one line, and the manifest says it exactly.
What host permission on youtube.com lets an extension do
Chrome's Declare permissions page, last updated 5 February 2024, lists what host permissions grant: fetch() requests from the extension service worker and extension pages, reading the url, title and favIconUrl properties of a tab, programmatic content script injection, network monitoring through chrome.webRequest, cookie access through chrome.cookies, and request rewriting through chrome.declarativeNetRequest. The same page records that patterns in content_scripts.matches produce the same warning as host_permissions.
The list is a ceiling rather than a description. An extension that declares https://www.youtube.com/* and nothing else has no access to any other origin, and one that never calls chrome.cookies cannot read cookies.
Host permission also excludes two things. Chrome blocks extension access to chrome:// pages, and access to file:// URLs and incognito windows stays off until the user enables it from the details page.
For a transcript extension, the sentence that matters is the warning Chrome generates from the host pattern: "Read and change your data on www.youtube.com". It comes from the manifest, not from the code, and it is not a report of what the code does with the access.
What each permission in a transcript extension grants
The permissions below recur in this category. The warning text is quoted from Chrome's Permissions reference, last updated 9 September 2026.
| Permission or key | What Chrome grants | Question to ask when you see it |
|---|---|---|
storage | The chrome.storage API. No install warning. Three areas: local writes to disk inside your Chrome profile, session is memory only and clears when Chrome closes, sync travels to every signed-in Chrome install | Which areas does the code call? A grep for storage.sync answers whether anything leaves the machine through your Google account |
tabs | Privileged fields on Tab objects: url, pendingUrl, title, favIconUrl. Warning: "Read your browsing history" | Which calls read those fields? Creating a tab needs no permission, so a tabs declaration for chrome.tabs.create alone is wider than the job |
activeTab | Temporary host access to the current tab after the user invokes the extension, revoked on navigation or close. No warning at all | Does the feature run only from a click, a context menu, a keyboard shortcut, or the omnibox? If yes, this is the narrower choice and its absence is worth noticing |
scripting | The chrome.scripting API for injecting files or functions, which also needs host permission or activeTab for the target page. No warning listed | How is the target page chosen? Injection into all frames of all tabs looks different in code from injection into the tab the user just clicked |
clipboardWrite | Copying and cutting through the web Clipboard API. Warning: "Modify data you copy and paste" | Is there a copy button the user pressed? An extension that writes to the clipboard on its own has no button to justify it |
clipboardRead | Pasting through the Clipboard API. Warning: "Read data you copy and paste" | Is paste an explicit action? A transcript extension that reads the clipboard is not gathering captions that way |
| Host permissions | The named origins, with the warning naming them. Match patterns in content_scripts.matches warn the same way | Which origins, and does the list match the job? https://www.youtube.com/* plus two prepublish.ai patterns is a different proposition from <all_urls> |
web_accessible_resources | Not a permission. A manifest key that exposes files inside the extension to web pages or other extensions. The default is that nothing is exposed | Is the array present? Browser extensions are fingerprintable through web accessible resources, which is why Chrome ships the safe default |
Three rows deserve more than a glance.
tabs overlaps with activeTab, and Chrome suppresses the tabs warning when the extension also requests <all_urls>, as the permission warnings page states. A broad extension can read every tab and show a dialog that never mentions browsing history.
clipboardWrite and clipboardRead carry separate warnings, and a reader scanning for "clipboard" can conflate them. Only the read side takes something from you.
web_accessible_resources is the row nobody reads, because it is not a permission and it never appears in a dialog. It decides whether a web page can reach into the extension's own files.
How to audit any extension in five minutes
The audit below ran on a real extension directory on 19 September 2026, and every output shown is what came back. The directory was the Prepublish extension source, which ships without a build step, so the files on disk are the files that run.
Step one, the store page. Open the listing and read the privacy panel, which is not the manifest. It lists the data categories the developer disclosed and three certification bullets about sale, unrelated transfer, and creditworthiness. A live listing checked on 19 September 2026 showed personally identifiable information, authentication information, and user activity. No permission string appears there.
Step two, find the extension on disk. Get the extension id from the store URL, or from chrome://extensions with Developer mode on. Then look under the user data directory, whose location chrome://version prints as Profile Path. The paths are:
| Platform | Installed extension directory |
|---|---|
| macOS | ~/Library/Application Support/Google/Chrome/Default/Extensions/<id>/<version>/ |
| Windows | %LOCALAPPDATA%\Google\Chrome\User Data\Default\Extensions\<id>\<version>\ |
| Linux | ~/.config/google-chrome/Default/Extensions/<id>/<version>/ |
On the machine used for this audit, that macOS path held four extension directories, and one had both 3.0.10_0 and 3.0.11_0 side by side. Chrome keeps the previous version folder after an update, so two releases of the same extension can be diffed in place.
Step three, read the manifest.
jq '{manifest_version, permissions, host_permissions, optional_permissions, web_accessible_resources}' manifest.json
On the Prepublish extension it printed manifest_version 3, three entries under permissions, four host patterns, and null for both optional permissions and web accessible resources. The values are in the worked example below.
Steps four to seven, four greps. These cover network calls, hosts referenced, dynamic code, script tags, and API namespaces.
grep -rn --include=*.js -E "fetch\(|XMLHttpRequest|sendBeacon|new WebSocket|EventSource" src
grep -rho --include=*.js -E "https?://[a-zA-Z0-9.-]+" src | sort | uniq -c | sort -rn
grep -rn --include=*.js -E "\beval\(|new Function\(|document\.write\(" src
grep -rn --include=*.html "<script" src
grep -rhoE "chrome\.[a-zA-Z]+(\.[a-zA-Z]+)?" src | sort | uniq -c | sort -rn
| Check | What came back on 19 September 2026 |
|---|---|
| Network primitives | 5 matches in 4 files: two thumbnail downloads, one caption refetch, and two lines that patch the request functions |
| Hosts referenced | youtube.com 10, prepublish.ai 8, i.ytimg.com 3, www.prepublish.ai 1, m.youtube.com 1, w3.org 1 |
| Dynamic code | 0 matches for eval(, new Function( and document.write( |
| Script tags | 3, all local modules: options.js, popup.js, workspace.js |
| API namespaces | 4: storage, runtime, tabs, contextMenus. No cookies, webRequest, scripting, history or downloads |
Two rows need a note. The single w3.org hit is the SVG namespace string, not a network destination, which is the first sign that this check produces noise alongside signal. The remote-code row covers half the rule: Manifest V3 also forbids remotely hosted code entirely, per Chrome's Improve extension security page, so a <script src="https://..."> inside an extension page would violate it with no eval in sight.
Step seven is the one worth keeping. An extension that declares cookies and never calls chrome.cookies carries a permission it does not need, and one that calls chrome.webRequest while declaring nothing that grants it will not work.
Step eight, watch it run. Right-click the extension icon, choose Inspect popup, open the Network tab, and use the extension. Then go to chrome://extensions, keep Developer mode on, and open the inspect link on the service worker row to watch the background context separately.
Which parts of transcript work need a server, and which do not
The split is not local good, server bad. It is about which operations have a reason to leave the machine.
Summarising or judging a transcript with a hosted model requires a server. The weights run on hardware you do not have, and no Manifest V3 extension can ship them or fetch them at runtime, so anything that returns prose about the meaning of a transcript sends the transcript somewhere. Prepublish's own site works this way, and the privacy page names the processors it uses for uploads and analysis.
Producing a public transcript page also requires a server, for a different reason. Prepublish pulls captions server-side with yt-dlp, and the public transcript API answers a cold request in 37.1 s and a cached one in 3.9 ms, measured on 19 September 2026. A shared 30-day cache is the point of that design, and a browser extension cannot share a cache between users.
None of that work is what a word count, a words-to-minutes conversion, a speaking-pace measurement, or a subtitle export needs. Those are arithmetic on text you already hold, and the extension performs them in the browser. The in-browser caption pull measures 1.4 s when the player's caption request is already captured, 14 s cold, and 26 to 38 s in a hidden background tab, measured on 18 and 19 September 2026.
The fair way to read a claim in this category is to ask which bucket the feature falls into. A summariser with no server is not a thing that exists. A word counter with a server is a choice.
The Prepublish extension, checked line by line
The Prepublish extension is a Manifest V3 package written in plain JavaScript and CSS with no build step and no dependencies. Its complete declared surface, read from its manifest.json on 19 September 2026, is three API permissions and four host patterns:
| Field | Value |
|---|---|
manifest_version | 3 |
permissions | storage, contextMenus, clipboardWrite |
host_permissions | https://www.youtube.com/*, https://m.youtube.com/*, https://prepublish.ai/*, https://www.prepublish.ai/* |
optional_permissions | none |
web_accessible_resources | none |
It declares no tabs, scripting, clipboardRead, webRequest, cookies, downloads or unlimitedStorage permission.
What it computes locally is counts, pace, and length. The header comment in src/lib/calc.js states the boundary: nothing in that file judges a script, and anything that would be an opinion is a hand-off to the website. The file touches no DOM, calls no chrome API, and imports nothing.
The caption pull is local in the sense that matters. A content script runs in the page's own JavaScript world at document_start and patches window.fetch and XMLHttpRequest.prototype.open to record any URL containing /api/timedtext. The extension then refetches the player's own URL with &fmt=json3 and credentials: 'include', so the request carries your YouTube session and goes to youtube.com rather than to Prepublish. It strips tlang, which the player appends for auto-translated captions, so the pull returns the track in the language the video is spoken in.
The one moment information about the video reaches Prepublish is when you open the public transcript page. The button opens prepublish.ai/youtube-transcript/<video id>, and the only thing about the video that crosses is the id in the address, along with attribution parameters naming the extension as referrer. No caption text, no draft, and nothing you typed is uploaded. Prepublish's servers pull the transcript on that page independently, so it is a second pull of the same public video rather than a copy of the one in your browser.
Two things it deliberately does not do matter as much.
The extension does not send the transcript anywhere, including to Prepublish. When you hand text to one of the free checks, the page loads with attribution parameters and the text is written into that page's own form field. The extension never submits the form. Every check on the site is free and needs no account, and the privacy page covers what happens after you press submit yourself.
The package also declares no web_accessible_resources and no host permission for YouTube's image host. Thumbnails load as ordinary image requests from the extension's own pages, which is why i.ytimg.com never appears in the permission list. With web_accessible_resources absent, no web page and no other extension can reach into the extension's files, which is the default Chrome ships and the one that keeps sites from fingerprinting extensions.
Where the audit stops
A privacy policy is a promise, and nothing in the browser enforces it. Chrome re-prompts for a new permission only when it triggers a warning, so a change that starts using access the extension already has arrives silently in an update, and the permission list describes a version you have not read.
The greps describe the files they ran against, and on a minified bundle the picture inverts. The same host-listing command against a bundled extension directory in the same Chrome profile returned hundreds of URL strings, mostly license headers, documentation links and specification references, and the most frequent hit was http://www.w3.org. On a minified bundle a grep tells you a string is present, not that it is reachable.
The Network tab shows what your actions caused. A request that fires on a code path you did not exercise, such as a first run, an error handler, or a specific video state, will not appear. It is the strongest available check and it is still a sample.
The permission dialog describes patterns, not behaviour. It names origins and capability classes and says nothing about what the code does with them. The gap between "can read youtube.com" and "reads only the caption track of the video the user asked about" is the entire privacy question, and only the code or the network tab closes it.
None of this argues against reading the permission list. Read it as the cheap first filter and treat the code as the answer. An extension that declares three permissions and makes five matched network calls in unminified source is auditable in five minutes.
Try it on your own script
Paste your draft below. You get your hook, structure, and pacing scores, a script-level attention-risk map, and the single biggest issue quoted from your own lines. Free, no login.
Free · No login · See a sample audit first if you prefer.
Frequently asked questions
What does a YouTube transcript extension that works locally actually do?
It reads the video page you already have open, takes the caption track URL that YouTube's own player requested, and refetches that URL from youtube.com with &fmt=json3. The request runs in your browser session, with your cookies, so the caption body travels from YouTube to your machine and nowhere else. Word counts, runtime from a pace, and pace measurement are arithmetic and run on the same machine. None of that requires a server, which is why the extension has none.
Does a Chrome extension need host permission to read a transcript?
It needs access to youtube.com, either as a declared host permission or as a content script match pattern, and either one triggers the same install warning. Chrome's Declare permissions page lists what host access grants: fetch requests from the service worker, reading a tab's url, title and favIconUrl, programmatic script injection, webRequest monitoring, cookies, and declarativeNetRequest rules. A transcript extension uses the first and the second. It does not need cookies, webRequest or injection to read a caption track.
What does the storage permission let a transcript extension do?
It grants the chrome.storage API, which Chrome's permission reference lists with no install warning. The extension can then keep data in three places. storage.local is written to disk inside your Chrome profile and survives restarts. storage.session is memory only and clears when Chrome closes. storage.sync travels to every Chrome install signed into your Google account. An extension that never calls storage.sync keeps your data on one machine, and you can check which areas it uses by grepping the source for storage.local, storage.session and storage.sync.
Is the permission list on the Chrome Web Store the same as the manifest?
No. The store's privacy panel shows data categories the developer disclosed, such as personally identifiable information, authentication information, and user activity, followed by three certification statements about sale and transfer. It does not print the permission strings from the manifest. Those appear in the dialog Chrome shows when you click Add to Chrome, which is generated from the manifest, and on chrome://extensions under the extension's details. For exact wording, read manifest.json on disk.
Can a YouTube transcript extension read my other tabs or my history?
Only if it declares the tabs permission or broad host permissions, and the tabs permission carries the warning Read your browsing history. Chrome does not show that warning when the extension also requests all_urls, so a broader extension can hide the tab-reading signal inside a wider one. The stronger check is the code. The extension audited for this article calls chrome.tabs only to create, query and remove tabs, and never reads another tab's URL.
Where does Chrome store an installed extension on disk?
Under the user data directory, in a per-profile Extensions folder. On macOS that is ~/Library/Application Support/Google/Chrome/Default/Extensions. On Windows it is %LOCALAPPDATA%\Google\Chrome\User Data\Default\Extensions. On Linux it is ~/.config/google-chrome/Default/Extensions. Each extension sits in a folder named by its 32 letter id, and inside that, one folder per version. Chrome keeps the previous version folder after an update, which makes a diff between two releases possible.
Do I need a server to summarise a YouTube transcript?
Yes, for the summarising. A hosted model runs on hardware you do not have, and its weights are not shipped inside a browser extension, so the transcript has to travel to the machine running the model. That is the honest reason summarisers in this category have servers. Counting words, converting words to minutes at a chosen pace, timing your own reading, and assembling a text or subtitle export are arithmetic operations. They have no such requirement, and moving them to a server is a choice rather than a necessity.
How do I check whether an extension sends my transcript anywhere?
Open the extension's own pages and its service worker in DevTools and watch the Network tab while you use it. Right-click the extension icon, choose Inspect popup, switch to Network, then pull a transcript and look at every request that leaves. On chrome://extensions, with Developer mode on, the service worker row has its own inspect link for the background context. Pair that with a grep of the source for fetch, XMLHttpRequest, sendBeacon and WebSocket, and you have both the static and the runtime view.
Related Articles
YouTube Transcript Extensions Compared: 15 Listings, Verified
The YouTube transcript extension category splits in two. Summarisers send the caption text to a server and return a digest, which needs an account and a provider that holds your text. Extractors read the caption track YouTube already served to your player and hand you the text.
YouTube MCP Servers Compared: 20 Public Servers, Verified
Twenty public MCP servers connect an AI client to YouTube, and eighteen of them fetch transcripts of videos that already exist. Only one accepts a script that has not been recorded.
What Is Inside a Generated Agent Skill File: A Real One
A generated agent skill file is a folder holding SKILL.md and a references directory, and the run torn down here produced 8,827 bytes of SKILL.md from 12 public uploads and 11 transcripts. The brief is worth reading, but two of its sections describe things the writer never received.
Free tools to put this into practice
Want to analyze your own scripts?
Start Script Analysis