- Lives in your system tray / menu bar
- Search GIFs from GIPHY and Tenor
- Click any GIF to copy the image itself β paste straight into Teams, Slack or Outlook and it arrives animated, not as a link
- Lightweight (~3 MB installer, ~30 MB RAM)
- Cross-platform: macOS, Windows, Linux
- Node.js 22+
- Rust (stable)
- Platform-specific dependencies:
- macOS: Xcode Command Line Tools
- Linux:
libwebkit2gtk-4.1-dev libgtk-3-dev librsvg2-dev - Windows: Visual Studio C++ Build Tools + WebView2
Grab the installer for your platform from the latest release.
The app is not signed with an Apple Developer ID, so Gatekeeper blocks it on first open. This is expected β right-click the app in Applications and choose Open, then confirm. You only do this once.
If macOS insists the app "is damaged and can't be opened", that is the quarantine attribute rather than a real problem:
xattr -cr /Applications/GifBar.app- Clone the repository
- Install dependencies:
npm install
- Optionally point the app at your own GIF proxy β it defaults to the deployed
one, so this is only needed if you are running the Worker locally:
cp .env.example .env # then set VITE_GIF_API_BASE=http://localhost:8787
The app ships no API keys. Vite inlines import.meta.env values into the
JavaScript bundle at build time, so a key referenced from the frontend ends up
in plain text inside every shipped .app and .exe, recoverable with strings
in seconds.
Instead, GIPHY and Tenor are called from a Cloudflare Worker in worker/,
which holds the keys as encrypted secrets and normalizes both providers into one
response shape. The desktop app only ever talks to that Worker. A leaked or
rate-limited key can be rotated with wrangler secret put β no new release.
The Worker deploys from CI β see worker/README.md for
the one secret it needs and how to set the provider keys.
npm run tauri devnpm testnpm run tauri buildThis produces platform-specific installers:
- macOS:
.dmginsrc-tauri/target/release/bundle/dmg/ - Windows:
.exeinstaller insrc-tauri/target/release/bundle/nsis/ - Linux:
.deband.AppImageinsrc-tauri/target/release/bundle/
Releases are cut by release-please from conventional commits β you never tag by hand.
- Land conventional commits on
master(feat:,fix:, β¦). - release-please keeps a release PR open with the version bump and changelog. Merging it is what cuts the release.
.github/workflows/release.ymlthen tags, builds installers for macOS (Apple Silicon + Intel), Windows and Linux, and uploads them to a draft release.- The
publishjob checks a.dmg,.AppImage,.deband.exeare all attached before flipping the release live.
The draft step matters: a published GitHub release is immutable, so assets have to land before it goes live.
Required GitHub Actions configuration:
| Name | Kind | Purpose |
|---|---|---|
TAURI_SIGNING_PRIVATE_KEY |
secret | signs updater artifacts (npx tauri signer generate) |
TAURI_SIGNING_PRIVATE_KEY_PASSWORD |
secret | password for the above |
CLOUDFLARE_API_TOKEN |
secret | deploys the GIF proxy Worker |
VITE_GIF_API_BASE |
variable | URL of the Worker β only if it is not the default |
Note that CI itself needs no secrets, which is what keeps Dependabot's builds green β Dependabot events get an empty secrets context.
- Tauri v2 β lightweight desktop framework (Rust backend, native webview)
- Svelte 5 β reactive UI framework (compiles to vanilla JS)
- Vite β frontend build tool
- Vitest β test framework
- Cloudflare Workers + Hono β the GIF proxy that keeps API keys off users' machines
See all releases here.

