Skip to content

Instantly share code, notes, and snippets.

@Davr1
Last active February 2, 2026 14:31
Show Gist options
  • Select an option

  • Save Davr1/af6a5806a3bf4b5b7dc18829029b42c2 to your computer and use it in GitHub Desktop.

Select an option

Save Davr1/af6a5806a3bf4b5b7dc18829029b42c2 to your computer and use it in GitHub Desktop.
Backup and restore discord favourite gifs

Backup and restore discord favourite gifs (last update: 27/01/2026)

How to use these scripts:

  1. Open a browser and log into your discord account.
  2. Open devtools using Ctrl+Shift+I (or Cmd ⌘ + Option ⌥ + I)
  3. Go to the console tab.
  4. Paste the snippet and hit enter. You might also need to type "allow pasting" if this is your first time using snippets.

Backup gifs

This snippet will export your favourite gifs into a file named discord-favorite-gifs.json.

window.FrecencyUserSettings ??= webpackChunkdiscord_app.push([[Symbol()],,e=>Object.values(e.c).values().map(m=>m.exports).filter(x=>typeof x=="object"&&x!=window&&x!=DOMTokenList.prototype).flatMap(x=>[x,...Object.values(x)]).find(x=>x?.ProtoClass?.typeName?.endsWith(".FrecencyUserSettings"))]);

function downloadJSON(content, download) {
  const json = JSON.stringify(content, null, 2);
  Object.assign(document.createElement("a"), {
    href: URL.createObjectURL(new Blob([json], { type: "application/json" })),
    download
  }).click();
}

FrecencyUserSettings.loadIfNecessary();
downloadJSON(FrecencyUserSettings.getCurrentValue().favoriteGifs.gifs, "discord-favorite-gifs.json");

Restore gifs

This snippet will ask you to pick a file with your (previously exported) gifs. It will merge them with the current set of favourite gifs, moving the old ones further down the list.

Note

If you generated your favourites file using a different tool/snippet it could be incompatible. Make sure it follows the specific structure that discord uses.

Click to view example
{
  // The object keys store the source urls - this is what gets sent in chat when you select a gif
  "https://tenor.com/view/cirno-fumo-touhou-fumo-touhou-gif-23545101": {
    // Gif format: NONE = 0, IMAGE = 1, VIDEO = 2
    "format": 2,
    // The media url - discord uses this to generate thumbnails in the gif picker
    "src": "https://media.tenor.co/videos/10b5a62192508ab85ec795ce4124f12a/mp4",
    // The thumbnail width
    "width": 640,
    // The thumbnail height
    "height": 358,
    // Numerical ordering index - gets incremented with each newly favorited gif.
    // This snippet automatically updates the indices of new gifs to always be higher than old gifs,
    // which does not affect their relative order.
    "order": 78
  },
  // ...
}
window.FrecencyUserSettings ??= webpackChunkdiscord_app.push([[Symbol()],,e=>Object.values(e.c).values().map(m=>m.exports).filter(x=>typeof x=="object"&&x!=window&&x!=DOMTokenList.prototype).flatMap(x=>[x,...Object.values(x)]).find(x=>x?.ProtoClass?.typeName?.endsWith(".FrecencyUserSettings"))]);

window._log = (msg, color) => console.log(`%c${msg}`, `font-size:2rem;color:${color}`);

function uploadJSON() {
  return new Promise((res, rej) =>
    Object.assign(document.createElement("input"), {
      type: "file",
      accept: "application/json",
      onchange: ({ target: { files: [file] } }) => file?.text().then(JSON.parse).then(res).catch(rej)
    }).click()
  );
}

uploadJSON()
  .catch(() => _log("Failed to parse JSON.", "red"))
  .then(gifs =>
    FrecencyUserSettings.updateAsync("favoriteGifs", state => {
      const offset = Object.values(state.gifs).map(g => g.order).reduce((a, b) => Math.max(a, b), 0) + 1;
      Object.values(gifs).sort((a, b) => a.order - b.order).forEach((gif, i) => gif.order = offset + i);
      Object.assign(state.gifs, gifs);

      const valid = state[Symbol.for("protobuf-ts/message-type")].toBinary(state).length <= 762880;
      if (!valid) _log("Too many gifs.", "red");

      return valid;
    }, 0)
  )
  .catch(() => _log("Unspecified/Network error.", "red"))
  .then(() => _log("Successfully imported gifs.", "green"));

Clear all favourite gifs

Caution

This action is irreversible. Backup your gifs before using this snippet.

Click to view snippet
window.FrecencyUserSettings ??= webpackChunkdiscord_app.push([[Symbol()],,e=>Object.values(e.c).values().map(m=>m.exports).filter(x=>typeof x=="object"&&x!=window&&x!=DOMTokenList.prototype).flatMap(x=>[x,...Object.values(x)]).find(x=>x?.ProtoClass?.typeName?.endsWith(".FrecencyUserSettings"))]);

FrecencyUserSettings.updateAsync("favoriteGifs", state => void delete state.gifs);
@taep96
Copy link

taep96 commented Jan 27, 2026

Nice work on the update!

there were some bugs with their implementation (namely that matching links using regexes would match both the source and media url

My last version reads the already-parsed data from localStorage, so there's no parsing bug. It also doesn't depend on webpack which should make it more stable, though it's read-only.

A better way to both read/write would be to send a GET/PATCH request to the API and use discord-protos for parsing, but that's tricky to do cleanly in a console script (CSP), and external tools add complexity. Probably not worth it for most use cases.

@Davr1
Copy link
Author

Davr1 commented Jan 27, 2026

Your localStorage snippet only worked on one of my discord instances and nowhere else :<
I think the :parsed: values were leftovers from a previous update, I can't even find what generated them in the code.

There's probably no easier way to parse the raw protobuf data in a snippet, sure I could compile and minify the schemas manually but that would bloat up the size and become harder to maintain. Maybe there's an undocumented flag on the frecency user settings endpoint to return the raw data, but once again a workaround has to be used to retrieve the token.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment