# From web tool to Chrome extension in a weekend

> World Time Buddy started life as our Time Converter website. Turning it into an extension was mostly about deleting UI, not adding it.

- Author: Ethan, Tech Lead · Mobile & Web
- Published: 2026-08-05
- Canonical: https://www.nexateam.dev/blog/from-web-tool-to-chrome-extension
- About: [World Time Buddy](https://www.nexateam.dev/work/world-time-buddy.md)

People kept telling us they had the Time Converter site pinned in a tab all day. That is usually a sign a tool wants to live closer to where the work happens. So one weekend we tried packaging it as a Chrome extension. This post is the build log, roughly as it happened.

## The weekend, as a timeline

1.  Saturday, morning**Decide what the popup is for**Look at saved zones, check one meeting time. Nothing else.
    
2.  Saturday, afternoon**Move the core into its own module**The time-zone maths already had no DOM access. It moved with a few import changes.
    
3.  Saturday, evening**Swap localStorage for extension storage**The only genuinely new code in the whole project.
    
4.  Sunday, morning**Cut the UI down to popup size**Search behind one input, saved zones first, timeline second.
    
5.  Sunday, afternoon**Store listing and screenshots**The part that took longest, and the part we should have done first.
    

The build, in order. The highlighted step is the only code that had to be written from scratch.

## A popup is not a page

The web version has room for a city search, a timeline across the day, saved zones and settings. A popup has roughly the width of a phone held sideways, and it closes the moment you click elsewhere. That changes the job completely.

Feature

Website

Extension popup

Saved zones

Sidebar list

First thing you see

Day timeline

Full width

Compact, below the zones

City search

Dedicated panel

One input at the top

Settings page

Yes

Removed, only a 12/24h toggle

## One core, two shells

1.  **Two shells**Different UI and storage, same behaviour
    
    `Website · localStorage``Popup · storage.sync`
2.  **Time-zone core**Plain TypeScript, imported by both
    
    `conversion``timeline``formatting`
3.  **Browser time-zone data**Comes from the platform, not bundled
    
    `Intl`

A fix in the core ships to both products.

## Storage that follows you

The website keeps saved zones in localStorage, which belongs to one browser profile on one machine. The extension uses sync storage instead, so zones follow the user to every computer where they are signed in. Listening for changes means an open popup updates without a reload.

```
const saved = await chrome.storage.sync.get("zones");
render(saved.zones ?? DEFAULT_ZONES);

chrome.storage.onChanged.addListener((changes) => {
  if (changes.zones) render(changes.zones.newValue);
});
```

1.  **Add a city**On your laptop
2.  **storage.sync**Chrome syncs the change
3.  **onChanged fires**On your other machine
4.  **Popup re-renders**No reload needed

How a saved zone travels between machines.

## Permissions we did not ask for

We requested storage and nothing else. The extension does not read the pages you visit or inject anything into them. Fewer permissions mean a shorter install prompt, an easier review and fewer reasons to hesitate.

> Every permission is a question the user has to answer. Ask as few as you can.

## What we would do differently

-   Write the store listing before writing codeIt forces the question of what the product is for.
-   Take screenshots at the required sizes from day one
-   Draft the privacy statement alongside the permission list
