| name | userscripts |
| description | Use when writing Tampermonkey/Violentmonkey/Greasemonkey userscripts, modifying website behavior or appearance, or working with .user.js files. |
Userscript Development
Guide for writing Tampermonkey/Violentmonkey userscripts.
Workflow
Phase 1: Requirements
Ask one at a time:
- Target site - URL pattern (e.g.,
https://example.com/*)
- Goal - CSS styling, add feature, remove element, keyboard shortcut, etc.
- Output location - Where to save the
.user.js file
Phase 2: DOM Inspection
Option A: Fetch URL directly (try first for public sites)
- Use WebFetch to retrieve page HTML
- Search for relevant selectors, CSS variables, data attributes
- Works for public sites not behind login
Option B: User provides MHTML/HTML file
- If fetch fails (login required, dynamic content), instruct: "Save the page (Cmd+S / Ctrl+S) as MHTML or 'Webpage, Complete'"
- Grep for patterns:
class=, data-, id=, -- (CSS variables)
- Prefer stable selectors:
data-testid, data-*, semantic IDs over generated class names
Option C: User provides selectors
- Guide user to inspect element in browser devtools
- Ask for: element selector, parent structure, relevant CSS variables
Phase 3: Implementation
- Choose
@run-at timing based on task type
- Choose
@grant level (start with none)
- Write script using metadata template below
- Save to user-specified location
Phase 4: Testing
- Instruct: "Install in Tampermonkey/Violentmonkey and reload the page"
- If issues: iterate on selectors or timing
Metadata Template
Full Templates
CSS Override (copy-paste ready)
;(() => {
'use strict'
const style = document.createElement('style')
style.textContent = `
/* Hide element */
.annoying-banner {
display: none !important;
}
/* Override CSS variable */
:root {
--site-font: -apple-system, BlinkMacSystemFont, system-ui, sans-serif !important;
}
`
document.documentElement.appendChild(style)
})()
DOM Manipulation (copy-paste ready)
;(() => {
'use strict'
document.querySelectorAll('.unwanted').forEach(el => el.remove())
document.querySelectorAll('a.external').forEach(link => {
link.setAttribute('target', '_blank')
})
document.addEventListener('keydown', e => {
if (e.target.matches('input, textarea, [contenteditable]')) return
if (e.key === 'j' && !e.ctrlKey && !e.metaKey && !e.altKey) {
e.preventDefault()
}
})
})()
Dynamic Content (copy-paste ready)
;(() => {
'use strict'
const processElement = el => {
}
document.querySelectorAll('.target').forEach(processElement)
const observer = new MutationObserver(mutations => {
for (const mutation of mutations) {
for (const node of mutation.addedNodes) {
if (node.nodeType !== Node.ELEMENT_NODE) continue
if (node.matches('.target')) processElement(node)
node.querySelectorAll?.('.target').forEach(processElement)
}
}
})
observer.observe(document.body, { childList: true, subtree: true })
})()
@run-at Timing
| Value | Use Case |
|---|
document-start | CSS injection, intercept before render |
document-end | DOM manipulation (DOM ready, images loading) |
document-idle | Non-critical, after page fully loads |
@grant Options
| Value | When to Use |
|---|
none | Simple scripts, no sandbox, direct page access |
GM_addStyle | CSS injection helper function |
GM_getValue / GM_setValue | Persistent storage across sessions |
GM_xmlhttpRequest | Cross-origin requests (also needs @connect) |
GM_registerMenuCommand | Add items to extension popup menu |
GM_setClipboard | Copy to clipboard |
unsafeWindow | Access page's JavaScript context |
Common Patterns
CSS Injection
const style = document.createElement('style')
style.textContent = `
.selector {
display: none !important;
}
`
document.documentElement.appendChild(style)
CSS Variable Override
const style = document.createElement('style')
style.textContent = `
:root {
--custom-property: value !important;
}
`
document.documentElement.appendChild(style)
DOM Query + Modify
document.querySelectorAll('.selector').forEach(el => {
el.style.display = 'none'
})
Keyboard Shortcut
document.addEventListener('keydown', e => {
if (e.target.matches('input, textarea, [contenteditable]')) return
if (e.key === 'j' && !e.ctrlKey && !e.metaKey && !e.altKey) {
e.preventDefault()
}
})
MutationObserver (Dynamic Content)
const observer = new MutationObserver(mutations => {
for (const mutation of mutations) {
for (const node of mutation.addedNodes) {
if (node.matches?.('.target-selector')) {
}
}
}
})
observer.observe(document.body, { childList: true, subtree: true })
GM_addStyle (with grant)
GM_addStyle(`
.selector {
display: none !important;
}
`)
Advanced Patterns
See @references/advanced-patterns.md for full implementations:
| Pattern | Use Case |
|---|
| Wait for element | Poll with requestAnimationFrame until element exists |
| isTyping helper | Skip shortcuts when user is in input/textarea |
| Scroll with offset | Smooth scroll accounting for fixed headers |
| Dark mode | CSS media query, meta tag, or CSS variables |
| URL parsing | Extract domain/path with new URL() |
| GM_addElement | Programmatic element creation |
| SPA navigation | Handle YouTube events, History API |
| Debug logging | Toggleable console output |
| Focus management | Track selection with keyboard nav |
| TreeWalker | Iterate text nodes for search/highlight |
| CSS Highlight API | Highlight without DOM modification |
| Canvas overlay | Draw scroll position markers |
Selector Strategy
Prefer (stable):
data-testid="value" - test IDs rarely change
data-* attributes - semantic, intentional
- Semantic IDs -
#main-content, #sidebar
- Tag + role -
button[role="tab"]
Avoid (fragile):
- Generated classes -
.css-1a2b3c, .sc-abc123
- Deep nesting -
div > div > div > span
- Index-based -
:nth-child(3)
Debugging Tips
- Test selectors in console first -
document.querySelectorAll('.selector')
- Check timing - if elements missing, try
document-idle or MutationObserver
- Inspect network - for dynamic content, elements may load after initial render
- CSS specificity - use
!important to override site styles
- Console errors - check devtools console for script errors
Reference
@references/api-reference.md - All metadata headers, @match patterns, GM_* functions
@references/advanced-patterns.md - SPA handling, dark mode, scroll markers, TreeWalker, etc.