Back to overview

Developing a Chrome extension to convert the current url to localhost in 1 click

Chrome logo repeated in a grid
| 4 min read
View count:


Often when I’m working on a project, I get bug reports of issues happening on production/acceptance environments with a URL pointing to the matching environment. The problem is that I have to copy the URL, remove the domain and paste it in my local environment and port to reproduce the issue. This is a tedious process, so I decided to create a Chrome extension to automate this.


I started out by creating a manifest.json file, which is required for every Chrome extension. This file contains the name, version, description, icons, permissions, etc. of the extension.

"manifest_version": 3,
"name": "Convert to localhost",
"description": "Convert your current URL to localhost",
"version": "0.0.1",
"action": {
"default_popup": "convert-to-localhost.html",
"default_icon": "128x128.png"
"options_ui": {
"page": "options.html",
"open_in_tab": false
"permissions": ["tabs", "storage"],
"icons": {
"16": "16x16.png",
"32": "32x32.png",
"48": "48x48.png",
"128": "128x128.png"

The action property is used to define the popup that is shown when you click on the extension icon. The options_ui property is used to define the options page of the extension. The permissions property is used to define which permissions the extension needs. In this case, we need the tabs permission to get the current URL and the storage permission to store the user’s settings. The icons property is used to define the icons of the extension. In the action’s HTML I reference the JavaScript file which I use to execute the logic of the extension. The port and the flag if HTTPS should be used come from the options of the extension (more on that below). It also displays the sentence “Converted URL to localhost” to give some feedback to the user.

<h1>Converted URL to localhost</h1>
<script src="convert-to-localhost.js"></script>

The JavaScript itself is also quite simple:

(async () => {
let queryOptions = { active: true, currentWindow: true };
let [tab] = await chrome.tabs.query(queryOptions);
const url = new URL(tab.url);
const port = (await"port")).port;
const secure = (await"secure")).secure;
url: `http${secure ? "s" : ""}://localhost:${port ?? "3000"}${

The options page is a simple HTML page with a form to set the port. The port is stored in the storage of the extension, so it’s persisted between sessions.

<label for="port">Port:</label>
<input type="number" id="port" name="port" />
<br />
<label for="secure">HTTPS:</label>
<input type="checkbox" id="secure" name="secure" />
<button id="save" type="submit">Save</button>
<script src="options.js"></script>

The JavaScript for the options page is only contains a few lines do to:

// Saves options to
const saveOptions = () => {
const port = document.getElementById("port").value;
const secure = document.getElementById("secure").checked;{ port, secure });
// Restores select box and checkbox state using the preferences
// stored in
const restoreOptions = async () => {
const syncItems = await["port", "secure"]);
document.getElementById("port").value = syncItems.port ?? "3000";
document.getElementById("secure").checked =;
document.addEventListener("DOMContentLoaded", restoreOptions);
document.getElementById("save").addEventListener("click", saveOptions);

Once the code was ready, the time had come to start testing it in Chrome. To do this, you have to go to chrome://extensions/, enable developer mode and click on “Load unpacked”. Then you can select the folder containing the extension and it will be loaded in Chrome. Now you can test the extension by clicking on the icon and setting the port in the options page.

When you change the source code, you do have to reload the extension by clicking the refresh icon on the extension in chrome://extensions/. Publishing to the Chrome store wasn’t really something I wanted to do for this extension, so that’s not covered in this article. Hope this was useful to you!

Source code can be found on GitHub.

Did you like this post? Check out my latest blog posts:

Person drawing flags on the ground
9 May 2024

Feature flags with Astro + Vercel Toolbar

5 min reading time

  • vercel
  • javascript
  • astro
Astral picture
29 Mar 2024

Astro DB: Migrating my analytics data from Vercel Postgres

5 min reading time

  • astro
  • database
  • vercel
  • postgres
  • libsql
Screenshot of an analytics dashboard
16 Jan 2024

Basic analytics with Vercel Postgres - Drizzle - Astro

10 min reading time

  • vercel
  • databases
  • typescript
  • astro