trendabc

Publishing TrendABC

Everything you need to get this into both stores. Do Firefox first — it is free, faster, and its reviewers catch things Chrome’s do not.

Can you skip the stores and just ship from GitHub?

For Chrome, no. For Firefox, yes.

Chrome only runs extensions Google has signed, and Google only signs what goes through the Web Store. Loading a .crx from a file or your own server has been blocked since Chrome 33 on Windows and Chrome 44 on macOS. What is left:

Route Who it reaches
Chrome Web Store — Public Anyone. Searchable.
Chrome Web Store — Unlisted Anyone with the direct link. Not searchable. Same $5, same review.
Load unpacked, Developer mode Only people willing to clone, build, and re-enable it. Chrome nags at every startup.
Enterprise policy force-install Only machines your organisation manages.

So “download it from GitHub” is a developer distribution channel, not a user one. Anyone who is not comfortable with chrome://extensions will not install it. This is why devo is in the store rather than telling people to build it — and it is the same reason to publish TrendABC there.

Unlisted is the useful middle step. Pay the $5, submit, publish unlisted, and you get a real install link to hand to a few people before going public. The review still happens, so it also flushes out permission objections early.

Firefox is genuinely different. Mozilla will sign an add-on you then host yourself:

# Get API credentials at addons.mozilla.org/developers/addon/api/key/
npx web-ext sign --source-dir .output/firefox-mv3 \
  --api-key "$AMO_JWT_ISSUER" --api-secret "$AMO_JWT_SECRET" \
  --channel unlisted

That returns a signed .xpi you can attach to a GitHub release, and users install it straight from there. It still passes through Mozilla’s signing, but it never appears in the AMO catalogue. --channel listed publishes it publicly instead.

Unsigned add-ons only load in Firefox Developer Edition, Nightly, or ESR with xpinstall.signatures.required disabled — not in normal Firefox.


pnpm zip            # → .output/trendabc-0.1.0-chrome.zip
pnpm zip:firefox    # → .output/trendabc-0.1.0-firefox.zip
                    #   + .output/trendabc-0.1.0-sources.zip

Before either submission, bump version in package.json. Both stores reject a version number that has already been uploaded, and neither lets you reuse one after a rejection.


Firefox — addons.mozilla.org

Free. No registration fee. Usually reviewed within a day or two.

  1. Sign in at addons.mozilla.org/developers
  2. Submit a New Add-onOn this site (listed publicly)
  3. Upload trendabc-0.1.0-firefox.zip
  4. Upload trendabc-0.1.0-sources.zip when asked for source code. This is required, not optional: the build is bundled by Vite, so reviewers cannot read the shipped file. Skipping it gets you rejected.
  5. Build instructions for the reviewer — paste this:

    Node 22, pnpm 10.
    pnpm install --frozen-lockfile
    pnpm build:firefox
    Output: .output/firefox-mv3
    
  6. Fill in the listing (see Store listing copy below)
  7. Submit

The manifest already declares browser_specific_settings.gecko.id and data_collection_permissions, both of which AMO requires. Confirm zero errors before you upload:

npx web-ext lint --source-dir .output/firefox-mv3

Updating later: bump the version, pnpm zip:firefox, upload both zips again under the same add-on.


Chrome Web Store — step by step

Budget: $5 once, about 40 minutes of form filling, then days to a couple of weeks of waiting. The permissions here put this at the slower end.

Step 0 — before you touch the console

These are the things that actually get extensions rejected. All but two are already done.

Then build the upload:

pnpm test        # must be green
pnpm build
pnpm zip         # → .output/trendabc-0.1.0-chrome.zip

Step 1 — register (one time, $5)

  1. Go to chrome.google.com/webstore/devconsole
  2. Sign in with the Google account that should own this extension forever. Transferring later is painful — do not use a throwaway.
  3. Pay the $5 developer registration fee. One time, covers the account, not per-extension.
  4. Set and verify the publisher contact email. This is not on the item’s pages — it lives on the developer Account page, and until it is done every item shows two blocking errors:

    You must provide a contact email before you can publish any item. You must verify the publisher’s contact email before you can publish any item.

    Fix it once, for the whole account:

    1. In the developer dashboard, open Account in the left sidebar (the gear / settings entry, not the item you are editing).
    2. Under Publisher contact information, enter the contact email.
    3. Save, then click Verify next to it.
    4. Google emails a confirmation link. Click it, then reload the item page — both errors disappear.

    This address is published on your listing, so use one you are happy to show publicly. It is where users and Google will contact you about the extension; it does not have to be the Google account you signed in with.

Step 2 — create the item

  1. Add new item
  2. Drag in .output/trendabc-0.1.0-chrome.zip
  3. It parses the manifest and creates a draft. Nothing is public yet.

Step 3 — Store listing tab

Field What to enter
Name TrendABC
Summary What's trending on GitHub, Hacker News, Reddit and arXiv — in one tab. Summarise anything with your own AI key.
Description the block under Store listing copy below
Category Productivity
Language English

Additional fields — all three are optional, but fill the last two. A listing with no support link looks abandoned before anyone installs it.

Field What to enter
Official URL None. This dropdown only lists domains you have verified you own, under Account → Verified domains. Skip it unless you own a domain and want it shown as verified. A github.com URL can never appear here — you do not own github.com.
Homepage URL https://github.com/abhishek-ch/trendabc
Support URL https://github.com/abhishek-ch/trendabc/issues

Screenshots — upload all five from store/screenshots/, in this order. The first is what people see in search results, so it leads with the product:

  1. 1-boards.png — the columns
  2. 2-signal-ranked.png — merged and ranked
  3. 3-summary.png — a summary streaming in
  4. 4-dark.png — dark theme
  5. 5-settings.png — bring your own key

Store icon — 128×128, use public/icon-128.png.

Small promo tile — 440×280, optional. It affects whether you can be featured. Skip it for v0.1.

Step 4 — Privacy tab (this is where submissions die)

Single purpose — paste exactly:

Replace the new tab page with a view of what is currently trending across developer news sources, and let the user summarise or ask questions about any item using their own AI provider API key.

Permission justifications — one box per permission. Copy these:

Permission Paste this
storage Stores the user’s settings, cached source listings, and saved summaries locally on their device.
unlimitedStorage Saved summaries accumulate without bound over time and would otherwise hit the default quota.
identity Optional Reddit sign-in through Reddit’s own OAuth consent screen, so the user can read their subscribed and private subreddits. Never invoked unless the user explicitly chooses to connect an account.
declarativeNetRequestWithHostAccess Removes the cross-origin Origin header from requests to reddit.com only, because Reddit’s bot filter rejects requests carrying it. The rule is static, declared in reddit-rules.json, and matches no other host.
Host permission (one box only — see below) The console gives a single box for all hosts. It must cover the news sources, the AI providers, and the optional wildcard together. Covering only the news sources is a mismatch against the manifest, and mismatches get rejected.

Host permission justification — paste this whole block into the single box:

The extension reads public listings from the news sources it displays:
github.com, hn.algolia.com, reddit.com, lobste.rs, export.arxiv.org and
huggingface.co. That access is read-only and the content is public.

It also needs api.anthropic.com, api.openai.com and openrouter.ai. These are
the AI providers the user chooses between. Requests are made only with the
user's own API key, and only when the user clicks summarise or sends a
message. No key is bundled with the extension and there is no backend server
of our own.

The broad optional host permission (*://*/*) is never requested at install.
It is requested at runtime, one origin at a time, only when the user asks for
a summary of a specific article, so the extension can read that one page's
text.

Are you using remote code?No. True only because the fonts are self-hosted in public/fonts/. If you ever re-add a <link> to Google Fonts or any CDN script, this answer becomes a false declaration.

Data usage — declare exactly these two, and nothing else:

Leave everything else unticked. No personally identifiable information, no location, no health, no financial, no personal communications, no web history, no user activity.

Then tick all three certifications — all three are true here:

Privacy policy URL — required because you declared data collection above. Paste the public URL of PRIVACY.md.

Do not claim you collect nothing. The extension stores API keys and transmits page text. Declaring that plainly is what passes review; a mismatch between your declaration and what the code does is the fastest rejection.

Step 5 — Distribution tab

Flip to Public later from the same tab; that flip needs another short review.

Step 5b — the submit dialog

Clicking Submit for review opens a confirmation with one checkbox:

☑ Publish “TrendABC” automatically after it has passed review

Leave it ticked if visibility is Unlisted — approval then puts it live at a link only you have handed out. Untick it if visibility is Public and you want to choose the moment it appears in the store.

The dialog also suggests narrower permissions shorten review. That is aimed at *://*/*, which is already optional_host_permissions and requested on click rather than at install. It cannot be narrowed further without dropping article summarising, so expect the slower end of the range.

Step 6 — after submitting

Things reviewers may come back on

Question Answer
Why override the new tab page? That is the product. The content is the new tab.
Why request access to all sites? Optionally, at runtime, only to read the article the user asked to summarise. It is not in host_permissions; it is optional_host_permissions and requested on click.
Is there a backend? No. No server, no analytics, no telemetry. Every request goes from the user’s browser to the source or to their own AI provider.
Whose API key is used? The user’s. None is bundled. Without a key, the summarise and chat features simply do not run.
Why modify request headers? One static rule stripping Origin for reddit.com, because Reddit rejects requests carrying it. No other host is touched, and nothing is blocked or redirected.

Store listing copy

Same text works for both.

Name: TrendABC

Summary (132 chars max):

What’s trending on GitHub, Hacker News, Reddit and arXiv — in one tab. Summarise anything with your own AI key.

Description:

TrendABC turns your new tab into a view of what is happening across developer news, right now.

BOARDS — one column per source: GitHub Trending, Hacker News, Show HN, Lobsters, Reddit, arXiv, and any RSS feed you add. Close a column and the rest share the width. Add one and they divide again.

SIGNAL — every board merged, deduplicated and ranked, so a story appearing on several sources at once rises to the top and is marked corroborated.

ASK ANYTHING — click any item to summarise it or ask questions about it, using your own API key for Anthropic, OpenAI or OpenRouter. Summaries are cached forever and free to reopen. Your key is stored locally and is sent to nobody but the provider you chose.

No account required. No server. No tracking. No telemetry. Open source, MIT licensed.

Category: Productivity (Chrome) · Other (Firefox)

Assets — all generated, nothing left to draw:


Before you submit either