Open-source project
ajayyy/DeArrow avatar
ajayyy/DeArrow

DeArrow replaces thumbnails with a frame from the video, and races two caches to get it

Crowdsourcing better titles and thumbnails on YouTube

2,296 stars84 forksTypeScriptGPL-3.0

At a glance

What is it?
The crowdsourced title and thumbnail extension works by storing a timestamp rather than an image, which is the design decision that makes it cheap, cacheable and portable across four platforms. The interesting engineering is the race between a remote generation service and a local canvas capture, and the honest detail is the fallback that shows a random non-sponsor timestamp.
Who is it for?
Use DeArrow if you spend real time on YouTube and are willing to submit and vote on titles, since the value of the extension is entirely the quality of the crowd's submissions and an empty database gives you the fallback behaviour instead of improvement.
Can I use it commercially?
Yes, with conditions. GPL-3.0 is a copyleft licence: if you distribute software that includes it, you must release that software's source code under the same licence. Running it internally without distributing it does not trigger that obligation.
Is it still maintained?
Yes. The repository last received commits 2 days ago.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 1, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A thumbnail is a timestamp, not an image

The central design choice is stated in one sentence: all thumbnails are just timestamps in a video, so they need to be generated. That single decision reshapes everything else. A crowdsourced thumbnail database stores a number per video and per submission instead of a file, so the storage problem is negligible, the moderation queue is a text field and an integer, and a submission from a phone is the same size as one from a desktop. It also makes the data portable across the four platforms the project ships, since a number means the same thing in a browser extension, a Safari app and an Android build. The cost is that the image has to be produced at display time, which moves work from the moment of submission to the moment of viewing, and that production is a rendering problem the extension has to solve locally, in a service, or both. It also explains the fallback. When nothing has been submitted, the extension takes a screenshot at a random timestamp, which is a frame nobody chose and which is often unremarkable but is at least honest about the video rather than a piece of clickbait artwork. You can configure that away, and the readme says so.

Two generation paths, raced

Thumbnails are generated one of two ways, and the readme says the extension tries both and uses the fastest. One path is a dedicated thumbnail generation service, which caches thumbnails for future requests so that the next user gets an instant result. The other is local generation, described as taking a screenshot of an HTML video element and drawing it to a canvas. A race between a remote cache and a local render is an unusual and sensible design. The remote path is fast for popular videos because somebody has already paid for the render, and the local path is fast for videos nobody has requested before, because it skips a network round trip entirely. Neither is reliable alone: the service can be unreachable, and local capture depends on the browser's canvas and video behaviour, which is precisely the sort of thing that differs between Chromium and Firefox. Racing them means the extension degrades to whichever is available. The cost is that you cannot reason about which path produced an image, and the extension will not know whether a frame it showed came from a cached render that is now stale or a fresh local capture. The repository carries separate submodules for the shared library and for the cache service, so the race spans two projects.

Titles are free text, and the fallback reformats rather than replaces

Titles work differently from thumbnails because a title is text the extension can always produce. A submission is any arbitrary text, and it is voted on by users the same way thumbnails are. When no submission exists, the extension formats the original title to a user-specified format, with title case and sentence case offered as the options, and the readme notes this can be disabled so the original is left alone. That is a much weaker intervention than a crowdsourced title, and the project is honest about the difference by saying the fallback formats rather than rewrites. The case conversion is worth a moment's thought, since shouting titles are a large part of what makes a feed unpleasant, and case conversion is something the extension can do locally and instantly with no data dependency at all. The other half of the mechanism is reversibility. If the original thumbnail is actually good, the readme says you can vote for it in the submission menu, and it then behaves like a submission. So a crowd can preserve originals as well as replace them, and one more control is added on top: a show original button appears when anything was changed, so you can see what YouTube originally served. Three layers of undo, which is the right instinct for an extension that rewrites a page you did not ask it to rewrite.

Group policy and a licence key, for organisations that reset browsers

There is a managed deployment section, and it exists for a specific reason. The readme points at the managed storage documentation for Firefox, the admin policy documentation for Chrome, and the enterprise extension settings documentation for Edge, and mentions an ad blocking filter list wiki page as further reading. The feature is that a licence key can be injected through group policy or managed storage, so the extension activates automatically even when its settings are reset on each install. That is the whole problem being solved: in an environment where browser configuration is redeployed on every machine refresh, a paid or donated extension that stores its state in user settings loses that state, and the extension reverts to defaults or disappears. Injecting a key through managed storage makes the state machine-managed instead of user-managed. It is also a signal about the project's economics, since the readme links a purchase page alongside the free download links, which means there is a paid tier and this is the mechanism for paying in a managed environment. What this does not tell you is what the key grants. That belongs to the website rather than the repository, and it is worth checking before you deploy it across an organisation.

Building it: submodules, a config file, and two bundlers' worth of scripts

The build instructions are precise and assume a current Node toolchain. The stated requirement is Node 22 with npm, and the first step is a clone that pulls submodules, which matters because the shared library is a submodule rather than a vendored directory:

bash
git clone https://github.com/ajayyy/DeArrow --recurse-submodules=yes

If you already have a clone, the equivalent submodule command is:

bash
git submodule update --init --recursive

Then copy the example configuration file to the real one and adjust it, and the readme adds a warning you should not skip: you will need to repeat that step in the future if you get build errors related to the configuration type. That is a symptom of a generated configuration type whose check is tied to a file that is not committed, and it will recur for any contributor who updates. Dependencies install with the lockfile-respecting command, then there are four build targets: a development build for Chrome with source maps, a development build for Firefox, and production equivalents of both. The output lands in a distribution directory, which you can load as an unpacked extension in Chrome or convert to a zip for Firefox as a temporary extension. The readme also mentions that for Firefox you may need to add parameters directly in the package manifest, which is a small but real sign that the two platform builds are not fully symmetric.

What is in the repository, and what is elsewhere

The top-level listing shows a normal extension project with a lot of neighbours. There is source, tests with a test configuration, public assets, a manifest directory, webpack configuration, editor and lint configuration, a continuous integration directory, an oss-attribution directory, and two tsconfig files, one for production. Then the parts that are not just this project. A gitmodules file and a maze-utils directory, which the readme identifies as a shared library with SponsorBlock, and which is why the clone needs the submodule flag. A config example file that you have to copy and keep in sync. A separate licence file for the app store distribution and another for historical licence terms, which is the practice of a project whose licence has changed and which needs to attribute code contributed under earlier terms. The related repository table is a map of an ecosystem rather than a single application: the extension itself, the shared library, a separate translations repository, a separate Safari project, the backend it fetches from, that backend's Kubernetes manifests, the thumbnail cache service, and that service's Kubernetes manifests. Read that table as the honest answer to how much is a browser extension. The extension is one part of a system with a backend, a cache, a translation pipeline and separate platform builds, all maintained by the same author.

Editorial conclusion

Use DeArrow if you spend real time on YouTube and are willing to submit and vote on titles, since the value of the extension is entirely the quality of the crowd's submissions and an empty database gives you the fallback behaviour instead of improvement. Do not adopt it in an environment where rewriting the interface is a problem, because a video that has been changed gives you a control to show the original but the video page itself is not the same, and because the extension is described as being in beta. Four things to verify. Where the data comes from, since the extension fetches from a backend run by the same author rather than from a first-party service, which is a trust decision about a separate project. Whether the thumbnail generation service is reachable, since the extension races it against local generation and the failure mode differs depending on which wins. What your fallback settings should be, because the default is a screenshot from a random timestamp, and the options can disable title formatting or show the original thumbnail instead. And, for a managed deployment, that group policy can inject a licence key so the extension survives a settings reset. The licence is GPL-3.0 and the last push was on 2026-09-21.

Frequently asked questions

How does DeArrow store and generate thumbnails?

All thumbnails are just timestamps in a video, so submissions store a timestamp rather than an image. The extension races a thumbnail generation service, which caches renders for later requests, against local generation that screenshots the video element onto a canvas, and uses whichever returns first.

What does DeArrow do when nobody has submitted a title or thumbnail?

It falls back to configurable options. By default it formats the original title to a user-specified case and uses a screenshot from a random timestamp that is not inside a SponsorBlock segment as the thumbnail. The readme says you can disable the title formatting or show the original thumbnail by default instead.

Can I see the original title and thumbnail in DeArrow?

Yes. The readme says a show original button is added if anything was changed, allowing you to see the original title and thumbnail. You can also vote for the original thumbnail in the submission menu, and it then acts as a submission.

How do I build DeArrow from source?

You need Node 22 and npm. Clone with the recurse-submodules flag, copy the example config file to config.json, run the lockfile install command, then run the development build for Chrome or Firefox. The output is in the dist directory, which you can load as an unpacked extension in Chrome or zip to load as a temporary extension in Firefox.

Which repositories does DeArrow depend on?

The readme lists a shared library with SponsorBlock, a translations repository, a separate Safari project, the backend it fetches data from, that backend's Kubernetes manifests, the thumbnail cache service, and that service's Kubernetes manifests. The shared library is a git submodule, which is why the clone command needs the submodule flag.

What licence is DeArrow released under?

GPL-3.0, and the readme credits being built on the base of SponsorBlock, licensed under GPL 3.0. The logo is based on an emoji set licensed CC-BY 4.0, and the repository carries separate licence files for the app store distribution and for history.

Official sources

  1. ajayyy/DeArrow on GitHub
  2. License: GPL-3.0
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/ajayyy-dearrow.svg)](https://hysenlabs.com/projects/ajayyy-dearrow)