Skip to content

Instantly share code, notes, and snippets.

@Davr1
Last active August 7, 2026 00:02
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: 31/07/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=>e.b&&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);
  const href = URL.createObjectURL(new Blob([json], { type: "application/json" }));
  Object.assign(document.createElement("a"), { href, download }).click();
  URL.revokeObjectURL(href);
}

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=>e.b&&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)
  )
  .then(() => _log("Successfully imported gifs.", "green"))
  .catch(() => _log("Unspecified/Network error.", "red"));

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=>e.b&&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

taep96 commented Jan 26, 2026

Copy link
Copy Markdown

queries the api instead of webpack so it shouldn't be as fragile:

const iframe = document.body.appendChild(document.createElement("iframe"));
const token = iframe.contentWindow.localStorage.token.replace(/"/g, "");
document.body.removeChild(iframe);

const response = await fetch(
	"https://discord.com/api/v9/users/@me/settings-proto/2",
	{ headers: { "Authorization": token } },
);
const { settings } = await response.json();
const urls = atob(settings).match(/https?:\/\/[^\s\x00-\x1f]+/g);

Object.assign(document.createElement("a"), {
	href: URL.createObjectURL(
		new Blob([JSON.stringify(urls, null, 2)], { type: "application/json" }),
	),
	download: "discord-favorite-gifs.json",
}).click();

@taep96

taep96 commented Jan 26, 2026

Copy link
Copy Markdown

closer to the original

const iframe = document.body.appendChild(document.createElement("iframe"));
const proto_2 = Object.entries(iframe.contentWindow.localStorage)
	.filter(([key]) => key.startsWith("UserSettingsProtoStore:parsed:2:"))[0][1];
document.body.removeChild(iframe);

const gifs = JSON.parse(proto_2)["favoriteGifs"]["gifs"];
const json = JSON.stringify(gifs, null, "\t");

Object.assign(document.createElement("a"), {
	href: URL.createObjectURL(new Blob([json], { type: "application/json" })),
	download: "discord-favorite-gifs.json",
}).click();

@Davr1

Davr1 commented Jan 27, 2026

Copy link
Copy Markdown
Author

Since this snippet is still relevant years later, I've decided to actually update this page. Big thanks to @taep96 for keeping it up to date, however there were some bugs with their implementation (namely that matching links using regexes would match both the source and media url - these are different and not usually interchangeable).

The updated snippet now exports the full object format again, which means that it can also be imported back into discord and transferred across different accounts.

I will try to not abandon this again lol.

@taep96

taep96 commented Jan 27, 2026

Copy link
Copy Markdown

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

Davr1 commented Jan 27, 2026

Copy link
Copy Markdown
Author

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.

@Bogo25

Bogo25 commented Apr 26, 2026

Copy link
Copy Markdown

I created a script that attempts to download them all. It fails downloading some of them but most will be downloaded successfully.
https://github.com/Bogo25/discord-favorite-gifs-dl/
Btw please add in the steps that allow pasting should be typed before the js snippet

@Davr1

Davr1 commented Apr 27, 2026

Copy link
Copy Markdown
Author

nice
discord recently changed something in their rspack config so I'll try to fix this snippet

@Davr1

Davr1 commented Apr 27, 2026

Copy link
Copy Markdown
Author

should work now

@N7NobodyCats

Copy link
Copy Markdown

should work now

which one do i use that works now? im not familiar with using github

@Davr1

Davr1 commented Jun 17, 2026

Copy link
Copy Markdown
Author

should work now

which one do i use that works now? im not familiar with using github

Scroll all the way up to see the original post. Here's the link to the snippet for downloading your favourited gifs as json: https://gist.github.com/Davr1/af6a5806a3bf4b5b7dc18829029b42c2#backup-gifs
And here's another project for downloading the original gif files based on that json: https://github.com/Bogo25/discord-favorite-gifs-dl/

@N7NobodyCats

Copy link
Copy Markdown

oh ok thanks, wasnt sure, since just above it, it said it was like 5 months old, and the latest message was only a couple months ago. wasnt sure if that was an old one or not

@chloricacid

Copy link
Copy Markdown

meow

@Davr1

Davr1 commented Jul 27, 2026

Copy link
Copy Markdown
Author

meow

:trollcatcozy:

@taep96

taep96 commented Jul 27, 2026

Copy link
Copy Markdown

meow

@beans-real

Copy link
Copy Markdown

meow

@LanaSama

LanaSama commented Aug 6, 2026

Copy link
Copy Markdown

I created a script that attempts to download them all. It fails downloading some of them but most will be downloaded successfully. https://github.com/Bogo25/discord-favorite-gifs-dl/ Btw please add in the steps that allow pasting should be typed before the js snippet

i just installed python wrong.. I installed the request module through python and got the script to run, however it fails for every gif saying the file/directory does not exist. I'll just post it as an issue on the script itself.

edit 2: on windows it downloads it to the root directory of the drive that you run the script (so c:\ or whatever), and if you don't run the script from there as well, it will fail to access. The exported json needs to be in that folder as well.

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