type: rule
status: active
timestamp: 2026-06-22
tags: [rule, shared-tenant, third-party, observability, no-per-app-projects, scale]

Shared-tenant-by-default for every 3rd-party service

Single shared tenant for every 3rd-party service

Shared-tenant-by-default for every 3rd-party service

Rule

For every 3rd-party SaaS service (Sentry, GA4, Microsoft Clarity, PostHog, UptimeRobot, Algolia, Substack, Stripe, Razorpay, Paddle, Cloudinary, ImageKit, etc.) the family uses ONE tenant. Apps separate by tag / label / custom-dimension / project-property, NOT by per-app account.

NEVER create per-app accounts/repos/properties when a tag-based shared tenant achieves the same separation.

Why

Implementation per service

ServiceShared tenantSeparation by
Sentry1 project for entire familytags: { app: '<slug>' } set in @chirag127/oriz-analytics init
GA41 propertyapp_slug custom dimension on every event
Microsoft Clarity1 projectapp: <slug> session-mask via clarity('set', 'app', slug)
PostHog (if adopted)1 project$lib_app property
UptimeRobot1 accountmonitor name = <app>:<endpoint>
Algolia1 applicationseparate INDEXES per app
CF Web Analyticsalready auto-aggregated by zonen/a
Substack1 newslettertags within posts
Razorpay1 merchant accountwebhooks identify app via notes.app
Cloudinary1 accountfolder-per-app

Apply via @chirag127/oriz-analytics

The analytics wrapper package handles the tag-injection automatically. Every app calls:

import { analytics } from '@chirag127/oriz-analytics';

analytics.init({
  app: 'oriz-paisa-finance-tools-app',  // ← single param; auto-tags all events
});

analytics.track('pdf.merge', { pages: 5 });
// Sentry: { app: 'oriz-paisa-finance-tools-app', event: 'pdf.merge', pages: 5 }
// GA4: app_slug = 'oriz-paisa-finance-tools-app', event_name = 'pdf.merge'
// Clarity: app set to 'oriz-paisa-finance-tools-app' for this session

One init call. Zero per-app account setup.

env vars

ONE set of env vars family-wide:

SENTRY_DSN=...                        # ONE Sentry project DSN
PUBLIC_GA4_MEASUREMENT_ID=G-...       # ONE GA4 measurement ID
PUBLIC_CLARITY_PROJECT_ID=...         # ONE Clarity project ID
PUBLIC_POSTHOG_KEY=...                # ONE PostHog project (if adopted)
PUBLIC_ALGOLIA_APP_ID=...             # ONE Algolia app
PUBLIC_ALGOLIA_SEARCH_KEY=...
RAZORPAY_KEY_ID=...                   # ONE Razorpay merchant
...

Set once. Synced via env-sync to all repos. Apps consume via process.env.SENTRY_DSN etc.

Exception: legitimate per-app separation

If two apps have legally-incompatible data (e.g. one is GDPR-strict EU-only, the other is India-only DPDP) → separate Sentry projects MAY be justified. Document the carve-out in the per-app knowledge folder.

Default = shared. Per-app = exceptional.

Cross-refs


Edit on GitHub · Back to index