Creating a custom Microsoft Edge (Chromium) extension using Azure Logic Apps and the Bing Image Search API for content

Photo by @cristina_gottardi / Unsplash.com

It’s summer in Finland now – a pleasant +15 C! Hopefully, it will be warmer in July. We put up a trekking tent on the balcony, and the kids are now sleeping there. So last night, they went to bed early, and I had some extra time to hack around a solution I’ve been meaning to build for some time now.

The solution

I wanted to try out building a custom extension to the new Microsoft Edge (Chromium) browser. As it’s based on the same principles as Google Chrome, mostly the same aspects and internals seem to apply – although there are obvious differences.

Browser extensions are client-side, so usually a mix of HTML, JavaScript and CSS files packed together.

My solution replaces the New Tab page in Edge, and shows a daily image picked from Bing’s Image Search API. I wanted to fully automate this, so I decided to use Azure as a sort of backend to serve those images.

This is how it looks when I open a new tab now.

Butwhy.gif, you ask? Well, the main driver was to get rid of the Bing search toolbar that is there by default. Too often I would open a new tab, and type in a few letters in the address bar and press enter, and the Bing toolbar would pick that up first and initiate a search on Bing. It was infuriating, so I set to get rid of the toolbar as I never seem to use it.

For reference, this is how Edge looks like with the default, built-in New Tab:

In essence, my solution would simply need to override the New Tab capability, pick up the daily image from Bing Image Search API and I’d be set.

Building the extension

I wanted to start fresh, so I created a new folder locally to store my extension. As I didn’t have Visual Studio Code yet installed, running winget, Microsoft’s new Package Manager, did the trick:

winget install "visual studio code"

Easy! I use VSCode when I modify static files, such as HTML and CSS. I found Creating a Microsoft Edge Extension guidance, and I actually read it all the way to the end before I realized it’s for the legacy Edge. It says this at the top of the article, but I was too anxious to just get started.

This page gives out the basics of creating an extension, with a truly nice tutorial to get you started. In essence, it’s quite straightforward.

First, you need to enable Developer Mode in Edge. Open edge://extensions and flip the switch on the lower-left corner.

You can now load custom extensions locally. Remember to turn off Developer Mode when you’re done!

Each extension needs a manifest.json that explains what the extension does, and what it requires. I created a skeleton manifest.json simply by copying the sample from docs.microsoft.com:

{
    "name": "New Tab",
    "version": "1.0",
    "manifest_version": 2,
    "description": New Tab with a daily photo from Bing"
}

Next, I set out to figure what permissions I’d need. I’ve learned over the years that minimal permissions is best. Turns out, to replace the New Tab-functionality you need to request for tabs permission, under permissions:

"permissions": [
    "tabs"
  ]

You can view the permission sets here.

I also need to override the New Tab/Ctrl+T feature, and this is done via chrome_url_overrides by requesting an override for newtab:

"chrome_url_overrides": {
      "newtab": "newtab.html"
  }

It needs to point to a local file, so I created a newtab.html in the same folder as manifest.json. I want to show a simple image, so my HTML is relatively simple:

<!DOCTYPE html>
<html>
    <head>
        <link rel="stylesheet" type="text/css" href="styles.css">
    </head>
    <body>
        <img src="URL GOES HERE" id="bg" alt="">
    </body>
</html>

I’m using a custom style sheet to position the image. Styles.css is thus simple also:

#bg {
    position: fixed; 
    top: 0; 
    left: 0; 
    min-width: 100%;
    min-height: 100%;
  }

I also added a browser_action tag in manifest.json so that I can have an interface for my extension, should I need it later on. This requires a separate HTML file. My manifest.json looks like this now when completed:

{
  "name": "New Tab",
  "author": "Jussi Roine",
  "version": "1.0",
  "manifest_version": 2, 
  "description": "New Tab with a daily photo from Bing",
  "chrome_url_overrides": {
      "newtab": "newtab.html"
  },
  "permissions": [
    "tabs"
  ], 
  "browser_action": {
    "default_title": "New Tab",
    "default_popup": "popup.html"
  }
}

popup.html can just have a <h1>Hello, world</h1> for testing it.

In newtab.html I’m pointing to an image, and this image is what I’ll pick from Bing.

Building the backend logic in Azure

In Azure, I created a new resource group called PhotoOfTheDay to hold my backend services. This should be easy – I need to pick up the image from Bing once per day, and store it somewhere for easy retrieval.

The Bing Image Search API is extremely useful, and you can play with it here. You can also install a Windows app to set the daily image as your Windows wallpaper. I found that the direct API that Bing exposes is http://www.bing.com/HPImageArchive.aspx?format=js&idx=0&n=1&mkt=en-US. format=js is useful as it sets the response payload as JSON, instead of XML. More modern, I guess.

I then built a simple Logic App, that calls the Bing API, extracts the URL of the image, retrieves the image, and saves that to a Storage Account. This satisfies the need I have within my extension, as the extension can now simply point to the Storage Account’s endpoint.

The Logic App looks like this:

Let’s quickly dissect this. I set recurrence to 12 hours, just in case I’d miss one image (perhaps running it at 23:59 and then at 0:01 on the day after).

Get Bing raw data is a HTTP action that calls the API:

Init PhotoURL Variable is an empty variable that I’ll use to store the URL to the daily photo.

I then need to parse the JSON that the Bing API returns. I use Parse JSON action for this:

And to get dynamic properties, I generated a schema based on the Bing API JSON (which you can get simply by opening the URL above in a browser session).

I’ll then populate the PhotoURL variable with the value of url from the JSON:

Now I have the full URL to the photo, and all I need is to retrieve it and store it in the Storage Account.

Looking in the container of the Storage Account, I now have a daily.jpg patiently waiting to be shown:

Finalizing the extension

I can get the URL to the photo in the Storage Account from the Copy button above, and I’ll modify the newtab.html to include it:

All I need to do is pack the extension at edge://extensions.

You’ll need to provide a local path to your extension, and you can omit the private key (if you’re not planning to distribute the extension):

And now the extension is listed as installed:

Pressing Ctrl+T shows the new tab with a daily image from Bing now! 🙂

In closing

Building a custom extension – a simple one – turned out to be very easy. I’m more certain now that I can build more complex extensions also, as I can leverage the power of Azure easily when needed. The Logic App runs in about 2 seconds now: