Loading tutorials…
Loading tutorials…
Custom properties are how Plausible lets you slice the data without GA4-level complexity. Logged-in vs anonymous, free vs paid, mobile vs desktop — every dimension you want to filter by needs to be a prop. Most owners never set them up. This is the walkthrough.
Who this is forOwners with Plausible Business plan who want to segment their data beyond the built-in dimensions (source, country, device, browser). Especially valuable for SaaS products where 'logged in vs logged out' or 'plan tier' is the key segmentation question.
What you'll need
Step 1
Custom properties are not events — they are dimensions you attach to every pageview/event. Pick 3-5 that you will actually filter by.
Bad starting points: "I will add every property I can think of in case I need it later." Each property is metadata on every event and clutters the filter UI.
Good starting points: "Plan tier is the question my CEO asks every Monday — I need plan_tier as a prop."
Common useful props for SaaS: auth_state (anonymous / logged_in), plan_tier (free / pro / enterprise), team_size (1 / 2-10 / 11-50 / 50+), industry (saas / ecommerce / agency), trial_state (none / active / expired).
Common useful props for ecommerce: cart_value_bucket (under_50 / 50-200 / 200_plus), is_repeat_customer (yes / no), traffic_source_class (paid / organic / direct).
Common useful props for content sites: content_category (blog / case-study / docs / pricing), reading_time_bucket (under_3min / 3-7min / 7_plus_min).
Resist the urge to track everything. 3-5 props is plenty.
Step 2
Custom properties on pageviews require the plausible.pageview-props.js variant. Custom properties on events work with any variant.
For pageview-level props (applies to every pageview automatically), use the plausible.pageview-props.js script variant. Update your script src to include it.
Example combined variant: <script defer data-domain="acme.com" src="https://plausible.io/js/script.outbound-links.tagged-events.pageview-props.js"></script>
For event-level props (only on specific events you call), no script-variant change needed — the basic plausible.js supports event props via the props parameter.
Verify the variant loaded: DevTools → Network → search "plausible.io/js" — confirm the URL includes pageview-props if you intend to use pageview props.
If the variant is wrong, pageview props will be silently dropped — they fire to the Plausible API but Plausible discards them because the receiving site is not configured to accept them.
Step 3
Before the Plausible script loads, set window.plausible_props = {plan_tier: "pro", auth_state: "logged_in"}. Every subsequent pageview will include these as props.
Add a small <script> block BEFORE the Plausible script tag. Set window.plausible_props with the props you want attached to every pageview.
Example: <script>window.plausible_props = {auth_state: "{{ user.is_authenticated ? 'logged_in' : 'anonymous' }}", plan_tier: "{{ user.plan_tier || 'none' }}"};</script>
The values must be set BEFORE the Plausible script loads. If you set them after, subsequent pageviews will include them but the first pageview will not.
For SPAs (React/Next.js/Vue), set window.plausible_props on app initialization (e.g. in useEffect on root mount). When the user logs in mid-session, update window.plausible_props — subsequent pageviews will reflect the new state.
Property names must be strings (no spaces — use snake_case). Values can be strings, numbers, or booleans. Plausible normalizes everything to strings in the dashboard.
Step 4
Pass props as the second argument to window.plausible(): plausible("Purchase", {props: {plan_tier: "pro", currency: "USD"}}).
For one-off events, pass props directly: window.plausible("Demo Booked", {props: {team_size: "11-50", industry: "saas"}}).
Event props are different from pageview props — they only attach to the specific event, not to subsequent pageviews.
Event props can also be combined with revenue: plausible("Purchase", {revenue: {amount: 49.99, currency: "USD"}, props: {plan_tier: "pro", first_purchase: "true"}}).
Naming conventions matter. Pick snake_case OR camelCase and stick with it. Plausible is case-sensitive — plan_tier and planTier are different properties.
Limit props per event to 30 maximum (Plausible enforces this). Realistically, 3-7 props per event is more than enough.
Step 5
In the dashboard, click the property name (e.g. plan_tier) to break down ANY report by that prop.
After props are flowing, navigate to your Plausible dashboard.
Scroll to the bottom — you should see a Custom Properties panel listing every prop with its top values.
Click a property name (e.g. plan_tier). The panel expands to show the breakdown: free = 8.2K visits, pro = 1.4K visits, enterprise = 320 visits.
Click a specific value (e.g. plan_tier = pro). The entire dashboard re-filters to just users with plan_tier = pro. Every other panel (Top Sources, Top Pages, Goals, Funnels) recalculates.
This is the killer feature: you can now answer "Where do pro-plan users come from?" / "What pages do enterprise users visit most?" / "What is the conversion rate for free vs pro?" without leaving Plausible.
Step 6
Inconsistent values explode the property breakdown ("pro", "Pro", "PRO", "pro-plan"). Pick a canonical form and enforce it server-side.
Inconsistent casing or formatting fragments the property breakdown. plan_tier = "pro" and plan_tier = "Pro" are different in Plausible.
Pick a canonical form (lowercase, no spaces) and enforce it in code. Best practice: define a constants file in your codebase mapping internal plan names to Plausible prop values.
Example: PLAUSIBLE_PLAN_NAMES = {free: "free", starter: "starter", pro: "pro", enterprise: "enterprise"}. Use this everywhere instead of free-form strings.
For values derived from user input (e.g. industry from a signup form), normalize before sending: industry.toLowerCase().trim().replace(/\s+/g, "_").
Audit the dashboard breakdown monthly for the first 90 days. If you see fragmented values, find the codepath and fix it. Plausible has no native value-normalization feature.
Step 7
Open DevTools → Network → /api/event. Inspect the payload. Confirm your props appear and have the expected values.
In an incognito tab (no plausible_ignore), visit your site as a logged-in user (if testing logged-in props).
Open DevTools → Network → filter "plausible". Click any /api/event request.
Inspect the Request Payload (Headers → Form Data section). You should see your props in the "p" field as a JSON object: p = {"auth_state":"logged_in","plan_tier":"pro"}.
If props are missing: check the script variant (pageview-props.js loaded?), the window.plausible_props timing (set before script?), and the prop names (no typos, case-correct?).
In the Plausible dashboard, navigate to your site. Wait 30 seconds. The Custom Properties panel should show your props with at least 1 hit each.
Common mistakes
Adding too many properties
What goes wrong: You add 12 properties (auth_state, plan_tier, team_size, industry, country, signup_date, last_login, feature_flags_X/Y/Z, AB_variant, ...). The dashboard custom-properties panel becomes a wall of noise. You stop filtering by any of them because there are too many to scan.
How to avoid: Limit to 3-5 properties that drive real decisions. Audit quarterly and remove props that have not been filtered on.
Wrong script variant — pageview props silently dropped
What goes wrong: You set window.plausible_props in your code. But you are still loading plausible.outbound-links.js (no pageview-props variant). Plausible accepts the pageview events but discards the props. Your dashboard custom-properties panel is empty.
How to avoid: Update the script src to include pageview-props: plausible.outbound-links.tagged-events.pageview-props.js. Verify in DevTools Network that the new variant URL returns 200.
Setting window.plausible_props AFTER the script loads
What goes wrong: You set window.plausible_props inside a React useEffect that runs AFTER the Plausible script has fired the first pageview. The first pageview has no props. Every subsequent pageview does. Your data has a hole at the start of every session.
How to avoid: Set window.plausible_props as early as possible — ideally in an inline <script> block BEFORE the Plausible script tag, or as the very first thing in your app initialization.
Inconsistent property values
What goes wrong: Your code uses 'Pro', 'pro', 'PRO', and 'pro-plan' as the plan_tier value across different files. The dashboard breakdown shows all four as separate values. You cannot tell which plan_tier is winning because the data is fragmented.
How to avoid: Define a constants file mapping internal plan names to canonical Plausible values. Use it everywhere. Never use free-form strings.
Tracking PII in custom properties
What goes wrong: You add email or user_id as a custom property. Plausible accepts it. Now you have a privacy regression — Plausible was supposed to be your no-PII solution and you just put PII in it. GDPR / SOC 2 audit risk.
How to avoid: NEVER put PII in custom properties. Use buckets and categories: auth_state = "logged_in" not user_id = "12345". team_size = "11-50" not company_name = "Acme Inc".
Forgetting to update props when user state changes
What goes wrong: User upgrades from free to pro mid-session. Your window.plausible_props still says plan_tier = 'free'. Their subsequent pageviews are attributed to free. Your conversion attribution is wrong.
How to avoid: On every state change (login, logout, plan upgrade, downgrade), update window.plausible_props with the new values. Subsequent pageviews will reflect the new state.
Recap
Done — what's next
How to set up Plausible goals and custom events
Read the next tutorial
Hand it off
Custom properties are the highest-leverage feature in Plausible Business plan and the one most owners never set up. Wiring them to your auth system and feature flags takes 3-5 hours of focused work — a vetted Plausible specialist on EverestX can do it cleanly for $60-120 at $14-16/hr.
See specialist rates
No additional per-property fee. Properties are metadata on pageviews/events you already fire — they do not count as extra events. The only requirement is Plausible Business plan ($19/mo+) which unlocks the feature.
Plausible enforces a hard cap of 30 properties per event. Realistically, 3-5 per pageview is the sweet spot. More than that and the dashboard becomes hard to scan.
No. Properties are recorded at event-firing time and stored immutably. New properties only attach to events fired AFTER you start setting them. There is no backfill.
You can filter the dashboard by any combination of property values and the entire dashboard recalculates. You cannot do free-text search across property values like GA4. For free-text search, the Plausible Stats API supports filtering by property combinations programmatically.
Custom properties. Separate sites per plan tier would mean separate billing, separate dashboards, manual cross-correlation. One site + plan_tier custom property is dramatically simpler and keeps all the data in one place.
Goals are events (something happened). Properties are dimensions on events (describing what happened). A user signing up is a goal. The user's plan_tier = 'free' is a property. Goals are billable; properties are not.
Plausible Analytics
Plausible's goal system is brutally simple — and that simplicity is what makes it powerful. Three types: pageview goals, custom events, and revenue goals. Most owners set up the wrong type, fire too many events, and blow past their plan. This is the discipline that prevents both.
Plausible Analytics
Plausible funnels are deceptively simple — you pick 3-8 goals, click Save, and it draws the chart. The real work is upstream: do the goals exist, are they ordered correctly, and is the funnel actually answering a question the team will act on?
Plausible Analytics
Plausible does not have a native Google Ads integration like GA4 does. It tracks UTMs on inbound links, full stop. Get the UTM templates right and Plausible delivers cleaner ad attribution than GA4. Get them wrong and your spend looks attributed to '(direct) / (none).'
Plausible Analytics
DIY Plausible is the right call up to a point. Then it isn't. This is the honest framework: when the cost of self-managing exceeds the cost of hiring, and how to tell which side you're on.