Chrome Extension Publishing Guide — Publishing Guide
21 min readChrome Web Store Publishing Guide
Complete guide from zero to published extension. Covers developer registration, store listing preparation, review process, updates, analytics, and monetization.
Table of Contents
- Developer Account Registration
- Preparing Your Extension for Submission
- Screenshot and Promotional Image Requirements
- Writing the Store Listing
- Privacy Policy Requirements
- Data Use Disclosure
- Review Process
- Responding to Reviewer Feedback
- Update Workflow
- Managing Multiple Versions
- Analytics Dashboard and User Metrics
- Handling User Reviews and Support
- Monetization Options
- Transferring Extension Ownership
Developer Account Registration
Before you can publish anything, you need a Chrome Web Store developer account.
Requirements
- A Google account (personal or Google Workspace)
- A one-time registration fee of $5 USD
- A verified email address
Registration Steps
- Go to the Chrome Web Store Developer Dashboard
- Sign in with your Google account
- Accept the developer agreement
- Pay the $5 registration fee via Google Payments
- Complete identity verification (required since 2023)
Identity Verification
Google now requires identity verification for all new developer accounts:
- Individual developers: Provide government-issued photo ID and a selfie for identity matching
- Business/organization: Provide business registration documents, your role verification, and a D-U-N-S number or equivalent
Verification typically takes 1-3 business days. You cannot upload extensions until verification is complete.
Account Limits
- New accounts are limited to publishing 20 extensions
- Accounts with a good track record can request limit increases
- Google Workspace administrators can manage developer accounts for their organization, which allows publishing under the company’s name
Preparing Your Extension for Submission
Before uploading, make sure your extension is ready.
Manifest Requirements
Your manifest.json must include:
{
"manifest_version": 3, // MV2 no longer accepted for new submissions
"name": "My Extension", // 75 characters max
"version": "1.0.0", // Semver recommended
"description": "Brief description", // 132 characters max
"icons": {
"16": "icons/icon-16.png",
"32": "icons/icon-32.png",
"48": "icons/icon-48.png",
"128": "icons/icon-128.png"
}
}
Icon Requirements
| Size | Where it appears |
|---|---|
| 16x16 | Favicon, tab bar |
| 32x32 | Windows taskbar |
| 48x48 | Extensions management page |
| 128x128 | Chrome Web Store listing, install dialog |
All icons must be PNG format with no transparency issues. The 128x128 icon is the most visible – invest in making it look professional.
Building the ZIP Package
The Chrome Web Store accepts a .zip file containing your extension files.
Do not include:
- Source maps (
.mapfiles) - Test files and test configuration
node_modules/.git/directory- Development configuration files (
.env,tsconfig.json, etc.) - Documentation and README files
A typical build script:
#!/bin/bash
# build-zip.sh
VERSION=$(node -p "require('./package.json').version")
FILENAME="extension-v${VERSION}.zip"
# Build the extension
npm run build
# Create the zip from the dist directory
cd dist
zip -r "../${FILENAME}" . -x "*.map"
cd ..
echo "Created ${FILENAME}"
Pre-Submission Checklist
- Extension works in Chrome stable (not just Canary/Dev)
- All declared permissions are actually used
- No
console.logstatements left in production code - Service worker handles errors gracefully
- Content scripts do not break popular websites
- The extension’s name does not infringe on trademarks
- Version number has been incremented from any previous submission
Screenshot and Promotional Image Requirements
Visual assets are critical for conversion. Users decide whether to install based on screenshots before reading the description.
Screenshots
| Requirement | Value |
|---|---|
| Minimum count | 1 |
| Maximum count | 5 |
| Size | 1280 x 800 pixels or 640 x 400 pixels |
| Format | PNG or JPEG |
| Recommended | Use 1280 x 800 for sharper display |
Tips for effective screenshots:
- Show the extension actually doing something useful
- Add brief text annotations highlighting key features
- Use a clean, consistent visual style across all screenshots
- First screenshot is the most important – it appears in search results
- Do not include the Chrome browser frame (just the content area)
- Avoid text-heavy screenshots that are unreadable at small sizes
Promotional Images
| Type | Size | Required? |
|---|---|---|
| Small promo tile | 440 x 280 px | Required |
| Marquee promo tile | 1400 x 560 px | Optional (required for featuring) |
The marquee tile is only used if Chrome editors choose to feature your extension. Include it anyway – you never know when they might pick yours.
Store Icon
Your 128x128 icon from the manifest is used as the store listing icon. It should be:
- Recognisable at small sizes
- Distinct from other extensions in your category
- Not a photograph or overly detailed image
- Consistent with your extension’s branding
Writing the Store Listing
The store listing is your sales page. Every field matters.
Name (Maximum 75 Characters)
- Be descriptive but concise
- Include a primary keyword (e.g., “Tab Manager” not “Tabify”)
- Do not include “Chrome” or “Extension” in the name (it is implied)
- Do not use ALL CAPS
- Avoid special characters and emoji
Short Description (Maximum 132 Characters)
This appears in search results. Make every character count:
Good: "Block distracting websites during work hours with customizable schedules"
Bad: "A really cool and awesome extension that helps you be more productive!!!"
Detailed Description (Maximum 16,384 Characters)
Structure it for scanning:
[Opening hook -- what problem does this solve?]
FEATURES:
- Feature 1: brief explanation
- Feature 2: brief explanation
- Feature 3: brief explanation
HOW IT WORKS:
1. Step one
2. Step two
3. Step three
PERMISSIONS:
This extension requests [permission] to [reason].
PRIVACY:
[Brief privacy statement with link to full policy]
SUPPORT:
[How to get help -- email, GitHub issues, etc.]
Category Selection
Choose the most specific category that applies:
| Category | When to use |
|---|---|
| Accessibility | Screen readers, magnification, colour changes |
| Blogging | Content creation, CMS integration |
| Developer Tools | Debugging, testing, code inspection |
| Fun | Games, entertainment |
| News & Weather | RSS readers, weather widgets |
| Photos | Image editing, screenshot tools |
| Productivity | Tab managers, note-taking, time tracking |
| Search Tools | Custom search, quick lookup |
| Shopping | Price comparison, coupon finders |
| Social & Communication | Social media tools, messaging |
Picking the wrong category can lead to rejection or poor discoverability.
Language and Localisation
- Set a primary language for your listing
- Provide localised descriptions for target markets
- Use
_locales/in your extension for UI strings - The store supports 55+ languages for listings
Privacy Policy Requirements
A privacy policy is required if your extension collects or transmits any user data.
When a Privacy Policy is Required
You must provide a privacy policy URL if your extension:
- Handles personally identifiable information (PII)
- Uses host permissions (accesses website content)
- Requests the
identityoridentity.emailpermission - Uses remote code or connects to external servers
- Uses analytics or tracking
- Collects any form of user data, even anonymised
In practice, almost every extension needs a privacy policy. If your extension
only uses storage for local preferences and has no host permissions, you
might be exempt – but providing one anyway is safer.
What the Privacy Policy Must Include
- What data you collect
- How you collect it
- Why you collect it (purpose)
- How you store and protect it
- Who you share it with (if anyone)
- How users can request data deletion
- How you notify users of policy changes
- Your contact information
Hosting Your Privacy Policy
Options for hosting:
- A page on your website
- A GitHub Pages site
- A Google Doc set to “anyone with the link can view”
- A dedicated privacy policy hosting service
The URL must be publicly accessible. Do not link to a page that requires login.
Data Use Disclosure
The Chrome Web Store requires a detailed data use disclosure that explains every type of data your extension handles. This appears on your listing page and is reviewed carefully.
Data Types
You must declare which of these data types you collect:
| Data Type | Examples |
|---|---|
| Personally identifiable information | Name, email, address, phone |
| Health information | Medical or health data |
| Financial and payment information | Credit card numbers, bank accounts |
| Authentication information | Passwords, credentials, security questions |
| Personal communications | Emails, messages, chat logs |
| Location | GPS coordinates, IP-based location |
| Web history | URLs visited, page titles |
| User activity | Clicks, mouse movements, scroll behaviour |
| Website content | Page text, images, DOM content |
Justifying Permissions in the Disclosure
For each permission that accesses user data, explain the purpose:
| Permission | Justification Example |
|---|---|
tabs |
“Reads the URL of the active tab to check if the current site is in the user’s blocklist” |
cookies |
“Reads authentication cookies for example.com to maintain the user’s login session” |
history |
“Reads browsing history to suggest frequently visited sites in the quick-access panel” |
bookmarks |
“Reads and writes bookmarks to sync saved articles across devices” |
| Host permissions | “Injects a content script on matching pages to highlight search terms” |
Certification
You must certify that your extension:
- Does not sell user data to third parties
- Does not use or transfer data for purposes unrelated to the extension’s core functionality
- Does not use or transfer data to determine creditworthiness or for lending
- Complies with Chrome Web Store policies
False certifications will result in removal of your extension and potential account suspension.
Review Process
Every submission goes through a review by Google’s team (automated and manual).
Timeline
| Submission Type | Typical Review Time |
|---|---|
| New extension | 1-5 business days |
| Update (no permission changes) | 1-3 business days |
| Update (new permissions) | 2-5 business days |
| Re-submission after rejection | 3-7 business days |
Review times can spike during holidays or after policy changes. Plan your releases accordingly.
What Reviewers Check
- Policy compliance: Does the extension follow Chrome Web Store policies?
- Permission justification: Does each permission have a legitimate use?
- Functionality: Does the extension do what its description claims?
- Malware/abuse: Does it contain malicious code or deceptive behaviour?
- Privacy: Is the data use disclosure accurate?
- Quality: Does it meet minimum quality standards?
Common Rejection Reasons
| Reason | What Went Wrong | Fix |
|---|---|---|
| Excessive permissions | Requested permissions you do not use | Remove unused permissions |
| Missing privacy policy | Extension handles data but has no policy URL | Add a privacy policy |
| Misleading description | Description claims features that do not exist | Update description to match reality |
| Single-purpose violation | Extension does too many unrelated things | Split into separate extensions or focus scope |
| Keyword spam | Stuffed irrelevant keywords in the description | Remove keyword stuffing |
| Trademark violation | Used a brand name without permission | Rename the extension |
| Remote code execution | Loaded scripts from external servers | Bundle all code locally |
| Broken functionality | Extension does not work as described | Fix bugs before resubmitting |
| Deceptive install | Install flow misleads users about what it does | Make the purpose clear |
| Insufficient description | Description is too vague or too short | Write a detailed description |
Remote Code Restrictions (MV3)
Manifest V3 strictly prohibits executing remotely hosted code. All JavaScript must be bundled in the extension package. You can still:
- Fetch data (JSON, configuration) from remote servers
- Use
chrome.scripting.executeScript()with code that is in the package - Load remote CSS (with some restrictions)
- Connect to WebSocket servers for real-time data
You cannot:
- Use
eval()ornew Function()with remote strings - Inject
<script>tags pointing to CDNs - Use
chrome.scripting.executeScript({ code: remoteString })
Responding to Reviewer Feedback
If your extension is rejected, you will receive an email with the reason.
How to Respond
-
Read the rejection email carefully. Identify the specific policy or requirement that was violated.
-
Fix the issue completely. Do not submit a partial fix hoping it will pass – it will not.
-
Update the version number. Even if the only change is a fix for the rejection, increment the version.
-
Re-submit with a note. Use the “Additional notes for reviewer” field to explain what you changed and why.
-
Be patient. Re-reviews often take longer than initial reviews.
Appealing a Rejection
If you believe the rejection was incorrect:
- Reply to the rejection email with a clear, factual explanation
- Reference specific Chrome Web Store policies
- Provide evidence (screenshots, code snippets) showing compliance
- Remain professional – combative responses rarely help
Appeals are reviewed by a different team member. Response time is typically 5-10 business days.
Common Mistakes in Re-Submissions
- Submitting without actually fixing the issue
- Changing the extension name to evade a trademark rejection
- Adding a permission that was previously flagged as unnecessary
- Not updating the privacy policy when data handling changes
- Submitting the same package with only a version bump
Update Workflow
Publishing updates follows a similar flow to the initial submission.
Version Bump
Always increment the version in manifest.json:
// Semantic versioning recommended
{
"version": "1.2.3" // major.minor.patch
}
Chrome also supports a four-part version: 1.2.3.4. The version must be
higher than the currently published version.
Upload and Publish Steps
- Build your extension ZIP (same process as initial submission)
- Go to the Developer Dashboard
- Click on your extension
- Click “Package” in the left sidebar
- Click “Upload new package”
- Upload the new ZIP file
- Update any store listing fields if needed
- Click “Submit for review”
Staged Rollout
For updates, you can use a staged rollout:
- After uploading, select “Publish to a percentage of users”
- Choose a percentage (e.g., 10%)
- Monitor crash rates and user feedback
- Gradually increase the percentage
- When confident, publish to 100%
This is invaluable for catching issues that only appear at scale.
Automating Uploads
Use the Chrome Web Store API for CI/CD:
# Install the Chrome Web Store CLI
npm install -g chrome-webstore-upload-cli
# Set environment variables
export EXTENSION_ID="your-extension-id"
export CLIENT_ID="your-oauth-client-id"
export CLIENT_SECRET="your-oauth-client-secret"
export REFRESH_TOKEN="your-refresh-token"
# Upload and publish
chrome-webstore-upload upload \
--source extension.zip \
--extension-id $EXTENSION_ID \
--client-id $CLIENT_ID \
--client-secret $CLIENT_SECRET \
--refresh-token $REFRESH_TOKEN
chrome-webstore-upload publish \
--extension-id $EXTENSION_ID \
--client-id $CLIENT_ID \
--client-secret $CLIENT_SECRET \
--refresh-token $REFRESH_TOKEN
Getting API Credentials
- Create a project in the Google Cloud Console
- Enable the Chrome Web Store API
- Create OAuth 2.0 credentials (desktop application type)
- Use the OAuth playground or a script to obtain a refresh token
- Store credentials securely (never commit to version control)
Managing Multiple Versions
You can maintain separate release channels for testing and stability.
Release Channels
| Channel | Audience | Purpose |
|---|---|---|
| Stable | All users | Production release |
| Beta | Opted-in testers | Pre-release validation |
| Dev | Internal team | Early development testing |
Setting Up Beta and Dev Channels
Each channel is a separate listing in the Chrome Web Store:
- Create a new item in the Developer Dashboard for each channel
- Use a different
nameto distinguish them (e.g., “My Extension Beta”) - Set the visibility to “Unlisted” or “Trusted testers”
- Use the
update_urlin the manifest to point to the correct channel
Trusted Testers
For beta testing with a controlled group:
- In the Developer Dashboard, go to “Distribution”
- Select “Trusted testers”
- Add tester email addresses (they must have Google accounts)
- Only these users can see and install the extension
Version Numbering Across Channels
Stable: 1.2.0
Beta: 1.3.0-beta.1
Dev: 1.4.0-dev.1
Chrome only compares the numeric version parts (1.2.0 vs 1.3.0). The
suffixes are for your internal tracking – they do not appear in the manifest.
Analytics Dashboard and User Metrics
The Developer Dashboard provides analytics for each published extension.
Available Metrics
| Metric | What It Shows |
|---|---|
| Weekly users | Active users who have the extension installed and enabled |
| Total installs | Cumulative install count |
| Uninstalls | Users who removed the extension |
| Weekly install/uninstall | Trend data for the past week |
| Impressions | Number of times your listing was viewed |
| Install rate | Installs divided by impressions |
| Ratings | Star ratings and review count |
| Browser version | Chrome versions used by your users |
| OS distribution | Windows, macOS, Linux, ChromeOS breakdown |
| Region | Geographic distribution of users |
Interpreting Key Metrics
Install rate (installs / impressions) is your most actionable metric:
- Below 5%: Your listing needs work (screenshots, description, or too many permission warnings)
- 5-15%: Average for most extensions
- Above 15%: Strong listing with good conversion
Uninstall rate: If more than 5% of users uninstall within the first week, investigate:
- Does the extension work as described?
- Is the onboarding clear?
- Are permission warnings scaring users after install?
- Are there performance issues?
External Analytics
For deeper insights, integrate your own analytics:
// Minimal, privacy-respecting analytics
async function trackEvent(event: string, properties?: Record<string, string>) {
// Only track if user has opted in
const { analyticsOptIn } = await chrome.storage.sync.get('analyticsOptIn');
if (!analyticsOptIn) return;
await fetch('https://your-analytics-endpoint.example.com/events', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
event,
properties,
extensionVersion: chrome.runtime.getManifest().version,
timestamp: Date.now(),
}),
});
}
Always provide an opt-out mechanism and disclose analytics in your privacy policy.
Handling User Reviews and Support
User reviews directly affect your store ranking and install rate.
Responding to Reviews
You can reply to reviews from the Developer Dashboard:
- Positive reviews: Thank the user briefly. Mention upcoming features if relevant.
- Bug reports in reviews: Acknowledge the issue, ask them to contact support with details, and provide your support email or link.
- Negative reviews: Respond professionally. Address the specific complaint. If you fix the issue, reply again asking if they would consider updating their rating.
- Spam or abusive reviews: Report them through the Dashboard. Do not engage.
Support Channels
Provide clear support channels in your store listing:
- Email: Simple and universal. Include a dedicated support email.
- GitHub Issues: Good for developer-oriented extensions. Users can search existing issues before reporting.
- FAQ/Help page: A web page answering common questions reduces support volume significantly.
- In-extension help: Add a help section or link in the extension’s popup or options page.
Managing Expectations
Set expectations about response time in your listing:
SUPPORT:
Email: support@example.com
Response time: Within 48 hours on business days
For bug reports, please include:
- Chrome version (chrome://version)
- Operating system
- Steps to reproduce the issue
- Screenshots if applicable
Monetization Options
The Chrome Web Store supports several monetization models.
Freemium
The most common model for Chrome extensions:
- Free core features available to all users
- Premium features gated behind a subscription or one-time purchase
- Handle license validation in your service worker
interface License {
tier: 'free' | 'pro' | 'team';
expiresAt: number | null;
features: string[];
}
async function checkLicense(): Promise<License> {
const { licenseKey } = await chrome.storage.sync.get('licenseKey');
if (!licenseKey) {
return { tier: 'free', expiresAt: null, features: ['basic'] };
}
const response = await fetch('https://api.example.com/license/validate', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ key: licenseKey }),
});
return response.json();
}
function isFeatureAvailable(license: License, feature: string): boolean {
return license.features.includes(feature);
}
One-Time Payment
Charge once for lifetime access:
- Simpler for users to understand
- No recurring revenue (limits long-term development funding)
- Use a payment provider (Stripe, Gumroad, LemonSqueezy) for licensing
- Deliver a license key after purchase
Subscriptions
Recurring revenue model:
- Monthly or annual billing
- Requires a backend to manage subscriptions
- Use Stripe, Paddle, or a similar provider
- Handle grace periods for failed payments
- Provide clear cancellation instructions
Implementation Considerations
- License validation: Check server-side, cache locally, re-validate periodically
- Offline access: Decide how premium features work when offline
- Grace periods: Do not immediately disable paid features on payment failure
- Refund policy: State it clearly in your listing
- Trial periods: Allow users to try premium features before paying
Chrome Web Store Payments (Deprecated)
The Chrome Web Store’s built-in payment system (Chrome Web Store Payments) has been deprecated. Use third-party payment providers instead.
Transferring Extension Ownership
Extensions can be transferred between developer accounts.
When to Transfer
- Selling an extension to another developer or company
- Moving from a personal account to a company account
- Team member leaving who owns the developer account
- Merging multiple developer accounts
Transfer Process
- Contact Chrome Web Store support: There is no self-service transfer.
Email chromewebstore-dev-support@google.com
with:
- Extension ID
- Current owner’s developer account email
- New owner’s developer account email
- Confirmation from both parties
- Requirements:
- Both accounts must be verified developer accounts
- The new owner must have paid the $5 registration fee
- The new owner must agree to maintain the extension’s policies
- What transfers:
- The extension listing and all its versions
- User base and install count
- Reviews and ratings
- Analytics history
- What does not transfer:
- Revenue from the old owner’s payment provider
- OAuth credentials and API keys (you must set up new ones)
- Support email settings (update these in the listing)
Group Publishing
To avoid the need for transfers when team members change, use group publishing:
- Create a Google Group for your development team
- Register the group as the publisher in the Developer Dashboard
- Add or remove team members from the group as needed
- The extension is owned by the group, not any individual
This is the recommended approach for any organization or team.
Before You Transfer
- Back up all source code (the Chrome Web Store does not let you download previously uploaded ZIPs)
- Document all API keys, OAuth credentials, and service accounts
- Notify your users about the ownership change in the extension’s changelog
- Update the privacy policy to reflect the new owner’s information
- Transfer any associated domains, analytics accounts, and support channels
Summary
Publishing to the Chrome Web Store is a multi-step process that rewards preparation. Register your developer account early, invest in your store listing, minimise permissions, write a real privacy policy, and plan for the review timeline. Once published, use staged rollouts for updates, monitor your analytics, respond to user reviews, and choose a monetization model that matches your extension’s value. Keep your listing accurate, your permissions minimal, and your users informed – that is how you build a successful Chrome extension. -e —
Part of the Chrome Extension Guide by theluckystrike. Built at zovo.one.