Developers

Manifest

A Pulsar extension has a normal manifest.json with one extra key, pulsar. Firefox ignores that key (with a warning), so the same file also loads in desktop Firefox.

A full example

manifest.json
{
  "manifest_version": 3,
  "name": "Price Watch",
  "version": "1.2.0",
  "description": "Tells you when saved items cost less.",
  "browser_specific_settings": { "gecko": {
    "id": "pricewatch@dealab.example",                        // required, never changes
    "update_url": "https://dealab.example/pulsar/updates.json"  // only for extensions outside the store
  } },
  "permissions": ["storage", "notifications"],
  "host_permissions": ["*://shop.example/*"],
  "background": { "scripts": ["pulsar.js", "background.js"] },   // pulsar.js first
  "content_scripts": [{ "matches": ["*://shop.example/*"], "js": ["content.js"] }],
  "options_ui": { "page": "options.html" },
  "pulsar": {
    "api": 1,                       // the Pulsar API version you speak (required to call the API)
    "permissions": ["background"],  // Pulsar permissions
    "tint": "#BE185D",              // your tile colour
    "icon": "shield",               // optional: a Pulsar icon instead of your own icon
    "engines": ["converter"]        // engines you call with engines.call
  }
}

The pulsar key

FieldTypeRequiredWhat it does
apinumberyes, to use the APIThe Pulsar API version your extension speaks. Today 1. Without it, calls to Pulsar are refused (not_allowed).
permissionsstring[]noPulsar permissions. Today only "background", for background jobs and schedules.
tint#RRGGBBnoYour tile colour in the extensions row, and the colour of media cards in your drawer.
iconstringnoA Pulsar icon name. Pulsar draws it on your tile instead of your own icon, so it matches the app in light and dark.
enginesstring[]noEngines you call, like ["converter"]. Shown at install as “Use the Converter engine”. See Engines.
Don’t ask for nativeMessagingOn Android that permission is only for Pulsar’s own built-in parts. The pulsar key is all you need; the store refuses files that ask for nativeMessaging.

Background scripts

Load pulsar.js before your own script. In Manifest V3 the background is an event page: it may sleep. Pulsar wakes it when it has something for you (the drawer opened, a setting changed, a scheduled check), and pulsar.js answers by connecting.

manifest.json
"background": { "scripts": ["pulsar.js", "background.js"] }
  • Register your Pulsar.on(...) listeners at the top level of your script, so they exist when Pulsar wakes you.
  • Send your specs again in Pulsar.onConnect(...): it runs on every (re)connection.
  • Manifest V2 with "persistent": true works too, but build new extensions as MV3 (see site access below).

Popup and options pages

KeyIn Pulsar
action.default_popupOpens in Pulsar’s drawer when the user taps your tile. One at a time; window.close() closes the drawer. Leave it out to use a native drawer (popup.set).
options_ui.pageShown in Pulsar’s drawer as your settings, unless you send a native settings spec with settings.set. Then runtime.openOptionsPage() opens it in a tab.
web_accessible_resourcesAs in Firefox. Use it for pages you open from a content script.

Popups only open on the user’s tap: action.openPopup() called by your code is ignored. A tile with no popup and no native drawer runs your action.onClicked handler, like Chrome.

Site access

People choose where an extension runs: All sites, Ask me or Selected sites, and Disable on this site for one site. For Manifest V3 extensions, Pulsar grants and takes back your real host permissions to match. Manifest V2 host permissions can’t be taken back, so Pulsar can only hide the extension: build MV3.

  • Ask for the narrowest patterns you need. Pulsar builds each site’s grant from your declared pattern (https://*/* becomes https://*.news.example/*).
  • With All sites, Pulsar can’t subtract one site from your permissions. It tells you instead (site.access and disabledSites in hello), and you must stop working there. The store checks this.
  • optional_host_permissions you ask for with permissions.request stay granted when the user agrees.

Ids and versions

  • browser_specific_settings.gecko.id is required. Use an email-like id on a domain you own. It can never change: it is how Pulsar, the store and updates know your extension.
  • Ids ending in @pulsarbrowser.com are kept for Pulsar.
  • Every upload needs a higher version than the last one (1.2.0 → 1.2.1).
  • A file from outside the store can never replace an installed store extension with the same id.

What Pulsar won’t install

  • Extensions from the Chrome Web Store, Mozilla’s store or Microsoft’s store. People see: “Pulsar only installs extensions made for Pulsar.”
  • Unsigned .xpi files (sign them, or use a Lite extension).
  • Files over 50 MB.