Browser permissions, explained
Every permission Emojery asks for, what the browser's wording actually means, and what the extension can never see.
The 6 permissions
| Permission | What it grants, in browser terms | What Emojery uses it for |
|---|---|---|
storage | Store data in your browser's extension storage | Your settings and per-site preferences, the signed-in session, a random installation identifier, your recently used emoji, local reaction state and a cache of counts about a minute old. Only the settings travel, through your browser's own sync; the rest stays on the device. |
unlimitedStorage | Lift the browser's default size cap on that extension storage | Keeping your reaction history on your device without the browser evicting it. Browsers show no extra warning for it, because it grants no new access. |
alarms | Wake the extension's background worker on a schedule | Two short wake-ups: retrying reactions queued while you were offline, and refreshing the list of most-used emoji at the top of the picker. |
activeTab | See the tab you are on, only when you open the extension | The popup reads the address of the tab you opened it on, so it can say whether the site is supported, offer that site's own toggle, and fill in the page a bug report is about. It is your click that grants it, and it reaches no other tab. |
scripting | Run the extension's own scripts, on the sites it already has access to | Only one job: the moment you install it, the supported pages you already had open get the reaction button without a reload. It reaches nowhere the host list below does not already cover, so browsers show no extra warning for it. |
identity | Open a sign-in window to a site the extension names, and read the address that window returns to | The Continue with Google, Apple, Microsoft or Twitch button. The window is the provider's own page; the extension sees only the short-lived code the provider hands back at the end, never your password there. |
What Firefox shows on the install page
Mozilla requires every extension to declare, in a fixed taxonomy, what data it may handle. Those labels appear on the add-on's install page and can sound broader than what actually happens:
- authenticationInfo: the short-lived code your provider hands back at the end of a provider sign-in, and the session token you get in exchange. They authenticate your reactions and nothing else.
- websiteContent: the public identifier of the post, repo, video, or product you react to. The extension reads the page only to find where to mount the button and to derive that identifier.
- technicalAndInteraction (optional) — the country, city, language, browser family and operating system attached to a reaction for aggregate maps. The extension's own “Community insights” setting starts on and can be switched off in settings; on Firefox, nothing is sent until you also grant this permission, which Firefox asks for separately.
We would rather explain the scary-sounding labels than pretend the extension collects nothing.
What the Chrome Web Store card shows
Google asks every developer to tick, from a fixed list of 9 data categories, the ones the extension "handles", and handling includes data that is only transmitted or only processed on your device. Emojery's card ticks 4. Each one, and what it stands for here:
- Authentication information: the short-lived code your provider hands back at sign-in and the session token the extension holds for 30 days afterwards. There is no password, and no name or email: the sign-in asks the provider for the standard
openidscope only. - Location: the country and city Cloudflare derives from your connection, stored with a reaction you submit while “Community insights” is on. Nothing finer than a city, no coordinates, and nothing at all when the setting is off. The per-address request limiter every request passes through uses the raw address on Cloudflare's rate-limiting service and holds nothing beyond a counter for the current window.
- Web history: 2 things. First, the canonical target key of each supported item that scrolls into view, sent to fetch its count without any account attached and answered without being stored or logged. Second, the pages you react on, which are stored with your reaction for as long as it stands, and the page a bug report is about. Nothing else about your browsing is stored, and the History tab in the popup never leaves your device.
- Website content: the content script reads the structure of a supported page to find the action row and derive the item's public identifier, and sends the item's canonical link with a reaction. It reads no text to send it, and nothing you type on a page.
The 2 we do not tick: Personally identifiable information, and User activity. The first because the sign-in never requests a name, an email or a picture, and the popup labels the account by its provider alone. The second because Google defines it as network monitoring, clicks, mouse position, scrolling or keystroke logging. Emojery records none of those: there is no analytics library, no click or scroll telemetry, and the only keyboard handling is the picker's own search box and focus trap. A reaction you submit is what you said, not a log of what you did, and the timestamps and change count on a reaction row exist so you can change or remove it. If Google's reading of the category ever differs from ours, the card changes, and this page changes with it.
The card also carries 3 certifications: that data is not sold to third parties outside Google's approved use cases, not used or transferred for purposes unrelated to the extension's core functionality, and not used to determine creditworthiness or for lending. The planned API is designed to keep all 3 true: it will serve the aggregate counts the public log already publishes and, at most, a per-country map of reactions with a minimum-count threshold, never anything tied to an account and never the city, language, browser or OS attached to a reaction.
Why it asks for access to specific sites
An extension that draws buttons inside a page needs a content script, and a content script needs host access to the pages it runs on. Emojery requests one https://<host>/* entry per supported host, plus
https://api.emojery.app/* so it can talk to its own API and https://emojery.app/* for our own site (what it does there).
Chrome, Edge, and Firefox all phrase host access as the ability to “read and change your data” on the listed sites. The wording is the browser's own, never ours, and it appears for every extension that has a content script. What the script actually does on those sites: it finds the action row of a public post, mounts the reaction button next to it, and derives the public identifier the reaction will attach to.
Each site's content script is also declared statically for that site's hosts only. The Reddit script cannot run on GitHub, and none of them can run on a site that is not in the list below.
Two settings you can turn on use that same access to touch the site's own controls, on the page you are looking at and under your own account: Hide original buttons takes the native control out of view, and Auto-press original buttons links the emoji you pick to the site's own reaction or vote. Auto-press is off until you turn it on, one pick presses at most one control, and removing your reaction releases only what the extension pressed. How auto-press works.
Which sites it can run on
Every host the reaction pipeline runs on, exactly as the manifest lists it. 2 non-platform entries sit alongside them: our API, and our own site (both below). Every platform name links to a page showing what the extension does there.
Apart from the 2 entries below, it runs nowhere else. A host that is not in the manifest is a host the browser will never inject the extension into.
The 2 entries that are not a platform
-
https://api.emojery.app/*: our own API. No content script runs there; the entry exists so the extension's background worker may call the endpoints that serve counts and accept reactions. -
https://emojery.app/*: our own site, and the only place besides the supported platforms where a content script runs. It does exactly 2 things, both on our pages only: it writes the installed extension version onto the page, so the site can say “already installed” instead of offering you the store link again; and that same marker lets a/reactlink hand a target to the extension. It reads no page content and sends nothing anywhere. It runs atdocument_startso the marker is there before our page looks for it.
What it does not read
- Page content, beyond the minimum. The script reads the page's structure only to find where the reaction button belongs and to derive the public identifier of the post, repo, video, or product. It does not scrape, index, or store what you read.
- Private messages, passwords, or form fields. Nothing you type on a page is read or transmitted.
- Private repositories. On GitHub and GitLab the picker does not show and does not react on private or internal repositories and projects: a reaction can only exist for a target the public can reach.
- Your browsing. Nothing is stored about pages you did not react on, and there is no tracking, advertising, or analytics library inside the extension. The count lookup described below is the one request a page you merely view produces, and it leaves nothing behind.
When a URL leaves your browser
Sometimes. Here is exactly when.
- Showing counts. As supported items scroll into view, the extension asks the API for each one's reaction count, whether or not you react to it. The request contains only a canonical target key, such as
youtube/<video-id>, and needs no account; the server answers it without storing or logging the key. While you are signed in, a second request asks which of those items you already reacted to, carrying your session token and up to 50 keys at a time, and is likewise not stored. - Reacting. When you pick an emoji, the request carries a canonical URL that the extension reconstructs from the identifier, with query strings and tracking parameters dropped. It sends
https://www.youtube.com/watch?v=<id>, never the raw address from your address bar, along with the emoji, a timestamp, your session token, and the random installation identifier described in the privacy policy. On X and Threads the canonical URL includes the author's handle, because every permalink there does; the server keeps the derived key, not the URL. - Signing in. The extension opens your provider's own sign-in page in a window and, when the provider hands back a short-lived code, sends that code to 1 endpoint in exchange for a session token. Your provider password never reaches the extension. What the server keeps afterwards is covered in the privacy policy.
- Reaction context. If the “Community insights” setting is on, which it is unless you turned it off, a reaction also carries your language, and the server attaches the country and city of your connection, your browser family and your operating system. Turn the setting off and those fields stay empty.
- Bug reports. The Report tab sends the page address, its host, the site it belongs to, how many targets were found on it, and your note, only when you press submit. With “Community insights” on it also attaches the extension version and your browser's raw user-agent string, so a layout bug can be reproduced on the same build; see what we collect.
Nothing above happens on unsupported sites, because the extension is not there.
What stays on your device
- Your reaction history: the popup's History list, kept in full on your device (this is what
unlimitedStorageis for) and never uploaded. - Your own-reactions map: which emoji you picked where, so the button can highlight your choice instantly.
- A short-lived count cache: about a minute, so repeated views don't re-ask the API.
- Your session token after sign-in.
- What this device calls each account: the emoji mark and name shown in the popup, and the settings that account changed away from the defaults, so two accounts on one browser keep their own. Names and marks are chosen here, not by the provider.
- The offline queue of reactions waiting to be sent.
Settings (the master switch, per-site toggles, animation and analytics preferences) sync through your browser's own extension-settings sync and never through our servers.
Turn it off on any site
Click the toolbar icon and open the Settings tab. Turning on Only selected sites gives every supported site its own toggle, and the master Enabled switch turns the extension off everywhere at once. All sites are on by default.
Your browser adds a layer of its own: Chrome and Edge let you restrict any extension's site access from the extensions menu, and Firefox does the same from the add-on's settings.
Delete your account any time
Open the popup's Account tab and choose Delete account. The extension shows a warning and asks you to slide to confirm, so a stray click cannot wipe anything. Deletion erases your account record, reverses every counter you previously contributed to, and clears the local history and session. Your entries in the public log stay, pseudonymous as they always were, each with a public revocation appended after it. It is immediate and irreversible; the details are in the privacy policy. Removing the extension is a separate step, and it leaves the account alone.
What the install prompt asks for
Browsers generate the install dialog themselves from the manifest, so every extension with a content script produces a similar warning. For Emojery the dialog lists exactly the domains from the table above plus our API and our own site, and nothing else.
There is no screenshot here yet, and it cannot be faked: that dialog is native browser UI, and a browser only draws it for an extension installed from a store. So here is the same content read straight off the manifest instead — the 28 domains a browser will name, in the order it receives them.
-
www.facebook.com -
m.facebook.com -
www.instagram.com -
instagram.com -
www.reddit.com -
reddit.com -
github.com -
gitlab.com -
www.youtube.com -
youtube.com -
x.com -
www.x.com -
threads.com -
www.threads.com -
www.amazon.com -
www.amazon.co.uk -
www.amazon.de -
www.amazon.fr -
www.amazon.it -
www.amazon.es -
www.amazon.ca -
www.amazon.com.au -
www.amazon.co.jp -
www.amazon.in -
www.amazon.com.br -
www.amazon.com.mx -
api.emojery.app -
emojery.app
Firefox prints Mozilla's data-collection notice above that list, using the labels explained further up. The 6 permissions in the first table add no line of their own, which is why the real dialog is shorter than this page.
Common questions
Does Emojery read all my browsing?
No. The extension can only run on the hosts listed in its manifest — the 14 supported sites, plus emojery.app, where a tiny script only stamps the installed version so our own site can tell you already have it. On those sites it asks the server for the counts of the items on screen and stores nothing about the ones you did not react on, and there is no all-sites permission to grant.
Why does the install prompt say it can "read and change" my data on these sites?
That is the browser's standard wording for any extension with a content script; it is not specific to Emojery. On those sites the script mounts the reaction button and derives the public identifier of the item you react to, nothing more.
Does it see private repos or private messages?
On GitHub and GitLab the picker does not show and does not react on private or internal repositories and projects. Direct messages are not a supported surface on any site, so no picker ever mounts there.
Is my browsing history uploaded?
No. The history list in the popup is stored only on your device and never uploaded. What the server does see is a count lookup for each supported item that scrolls into view, sent as a canonical target key rather than your page URL, with no account attached; it answers the lookup without storing or logging the key. The privacy policy describes both requests and what stays behind, which is nothing.
Can I limit it to just one or two sites?
Yes. In the popup's Settings tab, turn on Only selected sites and every supported site gets its own toggle; the Enabled switch above them turns the extension off everywhere at once. Your browser can additionally restrict the extension's site access on its own.
What do the Firefox data-collection labels mean?
They come from Mozilla's fixed taxonomy: authenticationInfo is your session token, websiteContent is the public identifier of what you react to, and there is no personallyIdentifyingInfo label because the sign-in never asks your provider for a name or an email. The optional technicalAndInteraction label covers the "Community insights" toggle, which Firefox asks about separately.
Why does the Chrome Web Store card list location and web history?
Because Google's taxonomy is broad and we fill it in literally. Location covers the country and city derived from your connection when you submit a reaction with "Community insights" on. Web history covers the public identifiers of items the extension asks counts for, and the pages you react on, which are stored with your reaction. Each category is explained below, including the one we do not tick.
Check it for yourself
The manifest is not a promise, it is a public file. Emojery is open source under GPL-3.0, and you can read the permission list, or build the extension from source, in the repository. Anything left over is answered in the FAQ.
The jargon-free overview puts each of these permissions back next to the feature it pays for.