Over the past 8 years, there has been precisely one constant in my new laptop setup: my background photo. It’s a photo I found in 2012 on National Geographic of a river house in Serbia. At the time, I was going through a steady phase of checking the National Geographic photo of the day every day. These days, I am no longer in such a phase. But, I miss the photo of the day.

This got me thinking. I rarely use the default chrome search bar that opens in new tabs. I figured I could save myself checking the photo of the day by building this chrome extension which would display it every time I opened a new tab.

Under the hood, chrome extensions are a zipped up .crx package of files (.json, .html, .js, etc). Each extension is required to have a manifest.json which is essentially a settings file.


My photo of the day manifest.json looks like this:

  "name": "National Geographic Background",
  "version": "1.0",
  "description": "Set the background on a new tab to the photo of the day!",
  "permissions": ["storage"],
  "chrome_url_overrides": {
    "newtab": "photo-of-day.html"
  "manifest_version": 2

Most of this pared down file is descriptive, but there are two parts relevant to this specific application.

As the name implies, permissions indicate what permissions an extension can access. My understanding of this is that they (surprisingly!) actually benefit both the browser and the developer to have. They define the capabilities of the extension and (critically for a javascript newbie like myself) limit the potential negative impact of a security vulnerability in the extension. The permissions should therefore be scoped to the smallest set of permissions strictly necessary. In my case, this was the ability to cache values across sessions which requires the (aptly-named) storage permission.

Overriding chrome://newtab

The crux of how this chrome extension works is the chrome_url_overrides value of the manifest json blog. Chrome provides three default pages: bookmarks, history, and newtab. Each of these can be accessed through the UI, or by prefixing chrome:// to the page type. (For example, navigating to chrome://bookmarks displays all bookmarks.)

Any single one of these can be overriden by a chrome extension, by pointing to a different page in the chrome_url_overrides section of the manifest. So, if this extension were instead rewriting history, it would read:

"chrome_url_overrides": {
  "history": "dear-republicans-please-go-back-to-2016-and-vote-again.html"

The html file referenced in the override will be what is rendered instead of the bookmarks, history, or newtab pages.

For my extension, the override points to a barebones html file which has minimal formatting, but critically injects a javascript file to scrape the url for the photo of the day.

Scraping National Geographic

This was my first time scraping using javascript so I’ll give the highlights for how that works! Using Chrome developer tools, I found that the url to the image itself is always in the photo of the day source code in a tag that looks like this:

 <meta property="og:image" content="https://www.nationalgeographic.com/path/to/photo.jpeg">

Simple enough! I used the fetch API to load the html from the photo of the day page, and then could use this little snippet to get the URL itself:


This worked! I spent all day yesterday opening new tabs just to see this beautiful image. But I did realize one small thing. Every time I opened a new tab, the extension scraped NatGeo again. I could instead cache the image value by using the chrome.storage API.

Caching URL

I could store the date and the url for the photo of the day. If the date was different, I would reload the url by scraping NatGeo. But, if the date was the same, I could just use the url I already had stored. This meant I needed the set and get functionality of the storage API. Here is a little snippet I used for the date:

chrome.storage.sync.get('date', function(result) {
	// Checks if date is unset, or the previous day, in which case will
	// pull the image source from nat geo
	var date = new Date().toISOString().slice(0, 10)
	if (result['date'] != date) {
		chrome.storage.sync.set({ 'date' : date }, function() {})

        // Load the new URL

That concludes my brief foray into Chrome extensions, javascript, and looking at beautiful photos. Feel free to install the Chrome Extension if you’d like (installation instructions are on the repo). If you have any thoughts or feedback on the extension, please create an issue in the Github repo.