Receive PostHog rage click events and forward them to Discord with human-readable alerts.
Rage clicks occur when a user repeatedly clicks on something that doesn't respond as expected. They're a strong signal of user frustration and often indicate:
- Broken buttons or links
- Slow-loading UI elements
- Confusing interface elements
- Missing click handlers
- Unresponsive form fields
- In your Discord server, go to Server Settings → Integrations → Webhooks
- Click New Webhook and copy the webhook URL
- Add it to this val's environment variables as
DISCORD_WEBHOOK_URL
- In PostHog, go to Data Pipelines → Destinations → Create Destination
- Select Webhook as the destination type
- Enter this val's endpoint URL:
https://valdottown--rage-clicks.web.val.run - Set up a filter for the
$rageclickevent
When PostHog detects a rage click, it sends a webhook payload containing:
- elements_chain: A complex CSS-selector-like string describing the clicked element
- $current_url: The page URL where the rage click occurred
- $pathname: The path portion of the URL
- Browser/device details: Browser, OS, viewport size
- Geo location: City, region, country (from
$set.$geoip_*fields) - Session info: Session ID, entry URL, user ID
This val:
- Parses the
elements_chaininto a human-readable description - Formats a Discord embed with all relevant context
- Sends an alert to your Discord channel
The elements_chain from PostHog looks like:
button.px-4.py-2:attr__class="..."attr__type="submit"attr__text="Save";form...
This val parses it into friendly descriptions like:
| Raw Element | Parsed Description |
|---|---|
button...attr__text="Save Changes" | "Save Changes" button |
input...attr__name="key"attr__type="text" | "key" input field |
svg.lucide.lucide-chevron-right... | Chevron Right icon |
a...attr__text="Docs"attr__href="/docs" | "Docs" link → /docs |
input...attr__type="checkbox"attr__name="agree" | "agree" checkbox |
The alert includes:
- 🖱️ Clicked Element: Human-readable description of what was clicked
- 📍 Page: The URL where it happened (clickable link)
- 🌍 Location: User's geographic location
- 💻 Device: Browser and OS info
- 📱 Screen: Viewport dimensions
- 👤 User ID: Identified or anonymous user
- 🚪 Session Entry: Where the user started (if different from current page)
Run shell.ts to send a test rage click event to Discord without waiting for real events:
# In Val Town, just run shell.ts
The test file includes several sample scenarios you can switch between:
// Choose which sample to test:
const eventToSend = sampleButtonClick; // "Save Changes" button
// const eventToSend = sampleInputClick; // "key" input field
// const eventToSend = sampleIconClick; // Chevron Right icon
// const eventToSend = sampleLinkClick; // "Getting Started Guide" link
The val exports types and utilities you can use:
import type { PostHogRageClickEvent } from "https://esm.town/v/valdottown/rage-clicks/main.ts";
import { parseElementsChain } from "https://esm.town/v/valdottown/rage-clicks/main.ts";
// Parse any PostHog elements_chain into a human-readable format
const element = parseElementsChain(event.elements_chain);
console.log(element.description); // '"Save Changes" button'
console.log(element.elementType); // 'button'
console.log(element.text); // 'Save Changes'
interface PostHogRageClickEvent {
event: {
uuid: string;
event: "$rageclick";
elements_chain: string;
distinct_id: string;
properties: {
$current_url: string;
$pathname: string;
$browser: string;
$browser_version: number;
$os: string;
$os_version: string;
$device_type: string;
$viewport_width: number;
$viewport_height: number;
$user_id?: string;
$session_id?: string;
$session_entry_pathname?: string;
$set?: {
$geoip_city_name?: string;
$geoip_country_code?: string;
$geoip_subdivision_1_name?: string;
};
// ... more properties
};
timestamp?: string;
};
}
- main.ts - HTTP handler that receives webhooks and sends Discord alerts
- shell.ts - Test script with sample rage click events for manual testing
- README.md - This documentation
If you want to link directly to session recordings, uncomment and configure the recording URL section in main.ts:
// Add link to PostHog recording if we have session_id
if (props.$session_id) {
const recordingUrl = `https://app.posthog.com/project/YOUR_PROJECT_ID/replay/${props.$session_id}`;
fields.push({
name: "🎬 Session Recording",
value: `[View in PostHog](${recordingUrl})`,
inline: true,
});
}
Replace YOUR_PROJECT_ID with your actual PostHog project ID.