Inject CSS and JavaScript into a web app
Pake CLI takes --inject with one or more local .css or .js files and bakes them into the app, so they run on every page it opens; the desktop app has the same thing under Advanced as Inject CSS and Inject JavaScript. CSS is the safe tool for hiding a banner or enlarging text, JavaScript can do more but breaks sooner, and you should only inject code you wrote or have read.
What --inject accepts
The CLI docs describe --inject as injecting local CSS and JS files, by absolute or relative path, into the page you pointed the app at. Two spellings are supported and they can be mixed:
# comma-separated
pake https://example.com --name Example --inject ./tools/style.css,./tools/hotkey.js
# repeated option
pake https://example.com --name Example --inject ./tools/style.css --inject ./tools/hotkey.js
Every file must end in .css or .js. In the source, a list containing anything else logs "The injected file must be in either CSS or JS format." and the injection step stops, so check the build output if your styles never show up. Relative paths are resolved against the directory you run pake from, not against the file that lists them.
The files are read at build time and copied into the app, so editing style.css afterwards changes nothing in an app you already built. Run the same command again to rebuild. If you keep your options in a JSON file, inject is a list of strings there too, and the CLI options page lists the rest of the flags.
What CSS is good for
CSS changes presentation and nothing else, which is why it is the first thing to try. Typical jobs are hiding a promotional banner, a cookie strip or a sidebar you never use, making the base font larger, or narrowing a wide column so text is easier to read:
.promo-banner { display: none !important; }
body { font-size: 17px !important; }
Find the selector in a browser first: open the site, inspect the element, and copy a class or attribute that looks stable. Prefer something like [data-testid="sidebar"] over a generated class such as .css-1x9k2f, because generated names change on every site deploy. Sites often set properties with specific selectors, so !important on the one property you want is normal here.
For zoom, you may not need code at all: every Pake app has zoom shortcuts, listed in the shortcut reference. The window customization guide covers the native options that never touch the page.
What goes wrong with JavaScript
JavaScript can click, remove or rewrite elements and add shortcuts, but it depends on the page's structure, and the page belongs to someone else. The usual failures:
- The site changed its markup. A script that finds a button with
querySelectorstops working the day the button gets a new class. It fails silently, so you notice only that the effect is gone. - Elements appear late. Modern sites render after load, so the element your script looks for may not exist yet. Observe the DOM or retry rather than checking once.
- Your code runs on every page. The same script runs on the sign-in page and the settings page, so guard it with a check such as
location.hostnameorlocation.pathname. - The page's own policies get in the way. A site can restrict inline styles or scripts with a Content Security Policy. Pake handles the style case: if the page blocks a
<style>element, its injector falls back to a constructable style sheet, except for CSS that uses@import, which still follows the page's policy. Test scripts separately; the style fallback does not establish whether a script can run.
Keep scripts short and defensive, and prefer CSS whenever CSS can do the job.
How Pake injects the files
When you pass --inject, the CLI wraps each file and concatenates them, in the order you gave them, into src-tauri/src/inject/custom.js inside the build workspace. A CSS file becomes a DOMContentLoaded listener that holds your CSS as a string and hands it to a helper, window.__PAKE_INJECT_STYLE__, which appends a <style> element to the document. A JS file is placed inside its own DOMContentLoaded listener as written, with the closing brace on its own line so a trailing // comment cannot break the wrapper.
At runtime Pake registers a list of initialization scripts on the web view. Leaving out a few scripts that only load with certain options, the order in the window code is: the Pake configuration, link and sign-in handling, the style helper, the toast helper, the event script, Pake's own style script and theme refresh, and last of all custom.js. So your code runs after Pake's, with the page's DOM ready, and your CSS comes later in the cascade than Pake's own rules. The built-in style.js also holds a few per-site tweaks that only apply on matching hosts, so a site you package does not pick up rules written for another one.
Because the files are compiled in, they are part of the app. Moving the app to another computer by copying the build output keeps them; the moving apps guide covers the desktop app's settings files.
Debug what you injected
Build with --debug, which the docs describe as enabling developer tools and detailed logging:
pake https://example.com --name Example --inject ./style.css --debug
In a debug build the developer tools toggle is available, on a Mac with Cmd Option I and on Windows and Linux with Ctrl Shift I; the shortcut table marks it as debug only. Open it, check the Elements panel for a <style> element or your rules in the computed styles, and read the Console for script errors. Edit the selector live until it works, copy it into your file, and rebuild. Release builds do not enable the toggle, so do not expect it in the app you ship.
The desktop app equivalent
In the Pake desktop app for Mac and Windows, Advanced holds Inject CSS and Inject JavaScript: your own styles and scripts, applied to every page the app opens. Click Edit on the app in My Apps, paste the code, and click Save Changes; editing reinstalls the same app in place. To remove a style that breaks a page, clear the field and save again.
Settings files carry the code too, but imported CSS and JavaScript stay off until you read them under Advanced and click Use Imported Code. That step exists because a file from someone else can contain anything.
Review scripts before running them
An injected script runs inside the pages of the site you wrapped, with access to whatever you are signed in to there. A script found online could read messages, or send data elsewhere, with no visible sign. Read every line before using a shared file, and keep scripts specific to one site. Pake documents that its native bridge is limited to the exact configured website origin, which narrows what a page can ask of the app, but the page itself is still fully scriptable by what you inject.
FAQ
Can I inject a remote URL?
No. The CLI reads each path from disk at build time, so download the file, review it and pass its local path.
Does the order of files matter?
Yes. They are joined in the order you list them, so a later CSS file overrides an earlier one when rules tie.
Do I rebuild after editing my CSS?
Yes for the CLI, since the file is compiled in. In the desktop app, edit the field and click Save Changes, which reinstalls the app with the new code.
