> ~ biozz / Blog

opensearch.xml in 2023 2023-07-10

Implementing opensearch.xml in the age of search engines monopolies

Reading time: 2m (393 words)

I am working on a tool which optimizes my workflow accessing various web resources. It is a combination of two things you probably already know about.

The first one is custom search engines. The simpliest form is https://google.com/?q=%s. %s is a placeholder which can be replaced by your search query. Then you are redirected to a search results page. The second one is aliases, when you can have some page aliased to a short word or even a letter, say. https://google.com/ becomes g.

Firefox is the one to implement them both. You can create a bookmark with an alias g something to search for something on Google, because it expands to https://google.com/?q=something.

It works okay for the most part. But I needed more:

  • more than one %s in a URL
  • a preview of an expanden URL
  • have an alias expansion history and stats

Anyway, I needed a cross-browser solution for the tool, because I don’t want to rely on Web UI and that I have to open a web page to use a tool. This is how I found opensearch.xml. It appears that it is still being used, but it depends on the browser.

You start by implementing an endpoint, which returns opensearch.xml:

var opensearchData string = `
<OpenSearchDescription xmlns="http://a9.com/-/spec/opensearch/1.1/"
  <Description>Just a bunch of links.</Description>
  <Contact>[email protected]</Contact>
  <Url type="text/html" method="get" template="http://localhost:3000/?q={searchTerms}" />
  <Url type="application/x-suggestions+json" rel="suggestions" template="http://localhost:3000/api/opensearch?q={searchTerms}" />

// OpenSearchFile serves opensearch.xml at `GET /opensearch.xml`
func (h *Web) OpenSearchFile(c echo.Context) error {
    c.Response().Header().Set("Content-Type", "application/opensearchdescription+xml")
	return c.Blob(http.StatusOK, "application/octet-stream", []byte(opensearchData))

You also add this to your index.html:


It seems that nobody fully supports the json-formatted responses. I as only able to get the first to elements to work (query string and completions).

  ["sears", "search engines"],
  ["7,390,000 results", "17,900,000 results"],
  ["http://example.com?q=sears", "http://example.com?q=search+engines"]

Firefox is the easiest to enable custom search. You use the special button in the address bar to add it.

Chrome is the tricky one. There is no way to add it by hand, it all happens automatically in the background when you first visit http://localhost:3000/?q=asdf. When Chrome sees the link tag it downloads opensearch.xml and adds the deactivated search engine. You can activate it and set your alias.

It is not possible to add custom search engine in Safari, you have to make an addon, which is unfortunate.