Portable Firefox search bookmarks and OpenSearch engines, without Sync https://pages.mstaff.de/public/search-bookmarks/
  • HTML 70.1%
  • Python 24.2%
  • CSS 5.7%
Find a file
Max Staff d317f8db06
All checks were successful
Deploy Pages / deploy (push) Successful in 3s
Record successful Firefox engine and bookmark import smoke test
2026-10-13 09:35:41 +02:00
.forgejo/workflows Add portable Firefox search bookmarks and OpenSearch setup site 2026-10-13 09:26:24 +02:00
research Record successful Firefox engine and bookmark import smoke test 2026-10-13 09:35:41 +02:00
site Add portable Firefox search bookmarks and OpenSearch setup site 2026-10-13 09:26:24 +02:00
.gitignore Add portable Firefox search bookmarks and OpenSearch setup site 2026-10-13 09:26:24 +02:00
build.py Add portable Firefox search bookmarks and OpenSearch setup site 2026-10-13 09:26:24 +02:00
check_suggestions.py Add portable Firefox search bookmarks and OpenSearch setup site 2026-10-13 09:26:24 +02:00
engines.json Add portable Firefox search bookmarks and OpenSearch setup site 2026-10-13 09:26:24 +02:00
README.md Record successful Firefox engine and bookmark import smoke test 2026-10-13 09:35:41 +02:00
style.css Add portable Firefox search bookmarks and OpenSearch setup site 2026-10-13 09:26:24 +02:00
test_build.py Add portable Firefox search bookmarks and OpenSearch setup site 2026-10-13 09:26:24 +02:00
test_suggestions.py Document Pages onboarding and test suggestion probe outcomes 2026-10-13 09:31:23 +02:00

Search bookmarks

A small, static Firefox setup page for devices that must not use Sync.

What the page offers

  1. One HTML download: imports a Search engines bookmark folder with all 18 search templates and preconfigured keywords. Desktop Firefox: Bookmarks → Manage Bookmarks → Import and Backup → Import Bookmarks from HTML.
  2. 18 OpenSearch installation pages: each advertises its engine through <link rel="search" type="application/opensearchdescription+xml">. Right-click the address bar → Add “SB …”, or use Firefox's search-engine dropdown / separate search bar's add-engine control. Clicking XML is not an install action. Each engine requires user confirmation.
  3. Mixed setup download: only the five searches with no configured suggestion endpoint; install the other engines individually if desired.

Bookmark keywords cannot supply remote suggestions. OpenSearch engines can, but Firefox does not import their aliases from XML. Assign @g, @y, etc. in Settings → Search → Search Shortcuts. The @ keeps them separate from imported bookmark keywords (g, y, etc.). Names are prefixed SB to avoid built-in engine name conflicts; nothing changes your default search engine.

Firefox no longer supports the old window.external.AddSearchProvider() page API. A static page cannot silently install a collection, import bookmarks, or change Firefox preferences. We deliberately do not offer a fake “install all” button, unsigned extension, or replacement search.json.mozlz4 profile file. Desktop installation instructions are provided; Firefox mobile does not have the same bulk bookmark import workflow.

Autocomplete findings

13 configured endpoints: 12 returned valid non-empty OpenSearch arrays in live probes; LEO is configured from Mozilla's definition but blocked the probe. Two of the 12 are explicitly general Google suggestions, not specialized search.

Searches Result
Google Direct Google suggestions verified
Google Bilder, Google Maps General Google suggestions, clearly labelled; not image/place autocomplete
YouTube Google ds=yt suggestions verified
Wikipedia DE / EN MediaWiki action=opensearch verified
Bing, DuckDuckGo, Ecosia, eBay Provider OpenSearch-compatible suggestions verified
Perplexity suggest.perplexity.ai/suggest verified
Startpage /osuggestions verified; /suggestions?format=opensearch returned 204
LEO Mozilla-configured strlist.json endpoint; HTTP 403 here, not live-verified
Amazon DE / US Current /api/2017/suggestions works but returns objects, not OpenSearch arrays; adapter required. Legacy /search/complete returned 404
IKEA No compatible public endpoint found; attempted search API routes returned 404
DHL Tracking-number lookup, no configured suggestions; no unrelated-provider fallback
Pathfinder No compatible endpoint found in the search page; original HTTP search retained because HTTPS certificate validation failed

The Amazon APIs are recorded as research URLs, never advertised as working OpenSearch suggestions. A static page cannot transform provider responses for Firefox. A future server adapter or browser extension would be a separate project with a different privacy/security model. We have not silently substituted Google for unrelated providers. Failed discovery is not proof an endpoint cannot exist, and a successful probe is not an uptime guarantee.

Exact URLs, findings, and status live in engines.json. research/suggestion-checks.json records the probe time, generic test query, HTTP status, format, and result count, not personal browser data. Search-result pages themselves have not all been end-to-end tested. A disposable Firefox 157.0.1 smoke test rendered the live homepage, installed all 18 published XML definitions through Firefox's search service, checked generated search/suggestion URLs, and imported/verified all 18 bookmark keywords through Firefox's own HTML importer. Native Add-engine UI confirmation and suggestion dropdown rendering were not automated. The normal browser profile was untouched.

Recheck providers

Requires Python 3.10+ (stdlib only). This explicitly sends the test query to the configured providers and the two Amazon research endpoints. It never runs on page visits or during deployment.

python3 check_suggestions.py --query berlin --strict \
  --output research/suggestion-checks.json

--strict fails if a previously verified/general endpoint no longer returns a non-empty valid array. LEO's known 403 and Amazon's adapter-required format are reported separately, not treated as successful OpenSearch responses. Update engines.json notes/status and rebuild if findings change.

Privacy

Stay signed out of Sync (or disconnect it before import); individual bookmark folders cannot opt out. Import does not disable telemetry, remote suggestions, Sync, or ordinary requests to search sites. Suggestions, when enabled, disclose unfinished queries to the provider before Enter. They go directly from Firefox to that provider, not through Pages. The website itself makes no provider calls. No cookies, account data, history, tokens, or ordinary bookmarks are exported.

The 18 searches combine nine original bookmark shortcuts and 12 registered engines, with three overlaps. All original keywords are preserved. Duplicate Google Maps/Images bookmarks are folded together; stale timestamp, tracking, viewport, and map-coordinate parameters were removed. DHL uses the current HTTPS piececode tracking URL instead of the old HTTP endpoint. Pathfinder's HTTP URL is explicitly flagged.

Build, test, preview

python3 build.py
python3 -m unittest -v
python3 -m http.server --directory site 8000
# Open http://localhost:8000/ (not a file: URL) to test discovery.

engines.json, build.py, and style.css are the source of truth. Generated site/ is committed because the existing Pages runner has Node, git, tar and curl, but not Python. Tests check keyword preservation, both imports, XML, discovery metadata, local links, escaping, absence of active content, and exact agreement between generated and committed files. Remove obsolete generated files if an engine is removed; the consistency test detects leftovers.

Forgejo Pages onboarding (one time)

This instance uses a custom token-scoped deployer, not automatic hosting merely because a repository or pages branch exists. This repository has been onboarded: public visibility, Actions enabled, repository deploy secret installed, and a public/search-bookmarks-only token hash registered with the deployer. The pages branch is protected with pushes limited to mstaff. The steps below document reprovisioning; do not generate another token just to publish an update.

  1. Push-to-create (requires the normal unlocked SSH identity):

    git push -u origin pages
    
  2. From the infrastructure repository, generate a new target-scoped token:

    docker/stacks/pages/new-target.sh public/search-bookmarks public-search-bookmarks
    

    Keep the raw token secret. Add only the printed hash/config entry to docker/stacks/pages/config/pages-deployer.yml, with target public/search-bookmarks, allowed ref refs/heads/pages, and allow_hidden: false.

  3. Apply the updated config on the Pages host, validate it with docker compose run --rm pages-deployer check-config, then reload with docker compose up -d --force-recreate pages-deployer. Preserve other targets.

  4. Set the repository Actions secret PAGES_DEPLOY_TOKEN, enable Actions, and protect the pages branch. Do not commit the raw token or store it in site/.

  5. Run the Deploy Pages workflow manually, or push to pages. The workflow packages only site/, not source, tests, research, or secrets, and uploads to http://pages-deployer:8080/deploy on runs-on: pages.

  6. Verify the public URL and one XML resource. If your web-server configuration enforces MIME types for OpenSearch, serve opensearch/*.xml as application/opensearchdescription+xml; the discovery link already declares that type. The existing Caddy static server normally serves XML as XML.

curl -fI https://pages.mstaff.de/public/search-bookmarks/
curl -fsS https://pages.mstaff.de/public/search-bookmarks/opensearch/google.xml

Push alone does not complete steps 2–5. No shared deployer configuration or existing site's deploy token is modified by this repository.

References