Genshin Impact · interactive maps

Synchronize your map progress.

Switching to a different Genshin map means starting from an empty one - hundreds of chests, oculi and puzzles you already found, all unticked again. This carries them over for you, so you pick up where you left off.

AppSample

Open map ↗

Community Genshin map. Progress lives in its Firebase cloud, tied to your Google sign-in.

Sign in on the map, open DevTools → Console, and run the snippet in the instructions below.

Firebase refresh token remembered in this browser.

Sync into AppSample

Mode

HoYoLAB

Open map ↗

The official Teyvat Interactive Map. Progress is tied to your HoYoLAB account session.

Open the map signed in, DevTools → Network, click a marker, copy the whole Cookie request header.

Cookie header remembered in this browser.

Sync into HoYoLAB

Mode

How it works

Every map stores progress as its own opaque ids, and none of them offer an import, so there is nothing to hand between them directly. Instead the tool pairs maps by position: it fetches every point each side publishes, works out the coordinate transform between them from the points themselves, and matches each thing you marked to the nearest point of the same category on the other map.

That last step is a nearest-neighbour match, so it is an approximation in principle. In practice the two maps turn out to be the same underlying survey, so the nearest point is almost always the same point: the median gap is 0.05 px on a map tens of thousands of pixels across. A match is only accepted inside a tight radius and only within the same category, and anything that fails those tests is reported as unmatched rather than guessed at - so the risk is a location left for you to do by hand, not a wrong one ticked off.

A few locations sit outside that radius even so - the same orb pinned a couple of metres apart by two sets of contributors. A second pass revisits only what the first one left over, within one category, and pairs two leftovers when each is the other's nearest by a clear margin. Where the leftovers cluster, it leaves them alone: an unmatched location is work left for you, a wrong pair is a lie written into your account.

Nothing is hard-coded to a game version. The transform is re-fitted on every run, including the separate offsets a few regions need.

  1. Authorize a map - paste its secret and press the button. The card shows how much that account has marked.
  2. Pick a source - the dropdown lists every other authorized map that can feed this one.
  3. Preview - see what would change, grouped by category. Nothing is sent.
  4. Sync - writes the difference. Re-running does nothing the second time.

The maps themselves are not authoritative. Their points are contributed and edited by players, so both sides carry mistakes: a marker a few metres from where the thing actually is, a chest recorded where a puzzle stands, a duplicate, a category someone picked wrongly, or a point one map simply never got. This tool copies what the maps say - it cannot tell a good point from a bad one, so those mistakes come across with everything else. Treat the result as a solid head start rather than a verified inventory, and expect a handful of oddities to sort out in game.

Respawning things are never transferred - ore, wood, plants, enemies, fish, animals. A mark on those means “farmed just now”, which starts a refresh timer, so importing them would write a timestamp that was never true.

Getting your secrets

Each map keeps progress against an account, so the tool needs the session your browser already has. Run the snippet for a map in its own tab, in the DevTools Console (Cmd + Opt + I on macOS, F12 on Windows).

AppSample - Firebase refresh token

Open the AppSample map signed in with Google, then run:

(() => {
  const r = indexedDB.open('firebaseLocalStorageDb');
  r.onsuccess = () => {
    const all = r.result.transaction('firebaseLocalStorage', 'readonly')
      .objectStore('firebaseLocalStorage').getAll();
    all.onsuccess = () => {
      const u = all.result.map(x => x.value).find(v => v && v.uid);
      if (!u) return console.error('Not signed in. Click "Sign in with Google" first.');
      console.log(u.stsTokenManager.refreshToken);
    };
  };
})()

It prints one long string. That is the token, and it is long-lived - you do this once.

HoYoLAB - Cookie header

Open the HoYoLAB map signed in, then DevTools → Network tab → click any marker on the map → find a request to sg-public-api.hoyolab.com → Headers → Request Headers → copy the full value of the Cookie: header.

Running copy(document.cookie) in the console looks like a shortcut, but the session token that actually proves you are logged in is httpOnly and invisible to JavaScript - that snippet silently drops it and pastes something that looks complete but fails with "please log in first". The Network tab above is the only reliable way to get it.

These are live logins. Treat them like passwords. They are remembered in this browser's localStorage so a reload re-authorizes without retyping, and are sent to this server only to make the requests you ask for - never written to its disk, never logged. Use Forget to remove one from this browser, which reopens the field so you can paste a different secret. On a shared machine, Forget when you are done.

Caveats

The two maps mostly agree on what a category is, and where they do not, the tool handles it rather than leaving the mismatch to you - in both directions. The ones marked note only are things no tool can fix, listed so a shortfall does not come as a surprise.

Seelie Warming Seelie

Handled

Warming Seelies are ordinary Seelies on AppSample

HoYoLAB files the 33 Warming Seelies under a category of their own. AppSample has no such category: all 462 of its Seelies sit under Seelie, which is exactly HoYoLAB's 429 Seelies plus those 33. They are paired as one category, so a Warming Seelie transfers like any other.

Mondstadt Liyue Inazuma Shrine of Depths Sumeru Shrine of Depths +4

Handled

Shrines of Depths are split by region on HoYoLAB

HoYoLAB gives each region its own Shrine of Depths category - Inazuma, Sumeru, Fontaine, Natlan, Borderland, Snezhnaya, and Mondstadt and Liyue under their bare region names. AppSample keeps all 70 in one. The eight are paired as one category, so a shrine transfers whichever region it is in.

Anemoculus

Note only

AppSample only records 54 of the 66 Anemoculi

There are 66 Anemoculi in the game and HoYoLAB lists them all. AppSample records only 54, so a sync into HoYoLAB carries everything you have marked and still leaves 12 unticked, and going the other way there is nothing on AppSample for them to land on. Those 12 are yours to finish by hand.

Anything a caveat does not cover is paired by its own category alone, and a location with no counterpart is reported as unmatched rather than matched to something else.