Privacy and your analytics choice
Updated 2026-10-21: clarified local storage for privacy choices and the tab-scoped maintenance-test exclusion flag described below.
What we collect
- Birth date, time, and city
- Used in temporary page memory to produce the chart. Birth city is not used in the calculation.
- Calculated chart
- Created locally in your browser and not stored anywhere on our side.
- URL
- Birth information is never placed in the address bar.
- Browser storage (without analytics)
- Until you allow analytics, we do not load the analytics or replay scripts or queue our analytics events. Your privacy choice is saved locally so it can be honoured on your next visit. An explicitly marked maintenance test also saves a single tab-scoped exclusion flag in
sessionStorage; it contains no birth data, URL, referrer, or user identifier. - Browser storage (with analytics)
- If you allow analytics, we store a single yes/no flag in
localStorageunder the keybazitrace.analytics.consent.v2. Google Analytics may set its own cookies after consent; Microsoft Clarity may set_clck,_clsk, and_cltkcookies after consent. Your prior v1 choice (bazitrace.analytics.consent.v1) is read once at first visit to decide whether to re-prompt — a v1 granted does NOT extend to v2 because v2 also covers Microsoft Clarity session replay; a v1 denied is honoured so the dialog does not re-appear on every page load. - AI explanation (optional)
- If you click Explain my chart with AI, a strictly-serialized derived chart is sent to our server and from there to a third-party language-model provider. Raw birth date, time, city, and any other input are not sent.
Information we do not request
Name, email, phone number, gender, account credentials, payment details, or a precise address.
How analytics work on this site
BaziTrace uses Google Analytics 4 (GA4) only after you click Allow analytics in the consent dialog. Until then, no Google Analytics script is loaded and no event is sent to Google. The dialog appears on your first visit.
- Manual page_view and page_context per route change after consent. After you grant consent, BaziTrace dispatches one GA4 standard
page_viewand one in-housepage_contextfor each route change. The manualpage_viewcarries onlypage_path,page_location, andpage_title. Google Analytics may also send its own standard or enabled automatic interaction events (such as enhanced-historypage_view,form_interactions, orsite_search) once you allow analytics; we cannot guarantee a server-side total of one event per route. The whitelist below covers our custom events only and does not list every parameter Google may attach to its automatic events. - No identifier tied to you. We do not pass your name, email, user id, birth data, or chart output.
- No advertising features. We do not enable Google signals, ads personalization, or remarketing.
- Transport is beacon. Events are sent via
navigator.sendBeaconwhen supported.
What we send to Google (when you allow analytics)
We send a small whitelist of low-cardinality event parameters. The whitelist below is the complete list — anything not on this list is rejected by the wrapper before it is sent.
- page_context —
page_id,page_type,schema_version(4),content_language. - navigation_click —
element_id,interaction_area,target_id. - calculator_start —
interaction_area,calculator_surface,content_language. Fires once per calculator page session, only after analytics consent is granted. Triggered the first time focus enters any form field on the calculator; if you submit without ever focusing a field, the submit handler still records it beforecalculator_submit.calculator_surfaceis one ofhome,day_master,ten_gods— the three documented entry points. - calculator_submit —
hour_known(yes/no),calculator_surface,content_language. Birth date, time, and city are never sent. This is the SUCCESS denominator — only fired after the chart engine produced a result. - calculator_submit_attempt —
hour_known,calculator_surface,content_language. Fires the moment you click Submit, after the duplicate-submit / in-flight guard and BEFORE any client-side validation. Paired withcalculator_submitso the funnel ratio issubmit/submit_attempt. Re-clicks while the engine is already running are not counted a second time. - calculator_field_complete —
field_name(birth_dateorbirth_time),calculator_surface,content_language. Fires at most once per (form instance, field) when you leave a date or time input whose value is non-empty AND passes the field's own validation rule. We never include the value, its length, or any derived field. Skipped when consent is not yet granted and not back-filled later. - calculator_validation_error —
error_type,calculator_surface,content_language. The full error message you see is local-only; only the coarse category reaches Google. - chart_generated —
hour_known,calculator_surface,content_language. The four pillars, day master, and element tally are never sent. - chart_summary_copy —
copy_result(success/failure),calculator_surface,content_language. Fires once per real copy attempt on the actual outcome of the clipboard write (thenavigator.clipboard.writeTextpath or thedocument.execCommand('copy')fallback). The summary text, chart contents, pillars, day master, and element tally are NEVER included. - faq_toggle —
element_id,target_id. - print_chart —
element_id. - scroll_depth —
scroll_percent(25/50/75/90/100), one per threshold per page. - content_engagement —
engagement_seconds(10/30/60), only while the tab is visible. - analytics_consent —
consent_state(grantedonly). The denial path does not send this event because strict opt-in means no event leaves the browser until you allow analytics. - page_view — the GA4 standard event. Carries only
page_path,page_location, andpage_titlefor the route. Emitted alongsidepage_contextexactly once per route change after consent. - ai_interpretation_request —
hour_known(yes/no),attempt(first/retry),calculator_surface,content_language. Fired when you click the AI button or Retry. No chart content, birth data, or AI output is included. - ai_interpretation_success —
latency_bucket,result_length_bucket,calculator_surface,content_language. Low-cardinality buckets only. - ai_interpretation_failure —
error_type,latency_bucket,calculator_surface,content_language.error_typeis one ofinvalid_request,disabled,timeout,rate_limited,upstream,bad_response,network,unknown. No provider error message is sent. - ai_typewriter_complete —
result_length_bucket,calculator_surface,content_language. Fires once when the response has been fully revealed in the browser.
What we never send to Google
Even when analytics is on, we never send:
- Birth date, birth time, or birth city.
- Any of the four pillar characters (the eight Chinese characters of the chart).
- The day master identity, element, or polarity.
- The five-element tally or any count derived from the chart.
- Free-text input from the calculator form.
- The AI interpretation text (the response from the language model).
- Provider request IDs, error messages, or upstream stack traces.
- Any name, email, phone, address, or account identifier — we do not collect them in the first place.
The analytics wrapper has a deny-by-default validator that drops any value matching a date, time, or CJK character pattern, so an accidental misuse cannot leak chart data to Google.
AI explanation (optional, click-triggered)
On the /chart page, after a chart has been calculated, you may click Explain my chart with AI. That single click sends a strictly serialized version of the chart to our server, which then forwards it to a third-party language-model provider (MiniMax) for a short English explanation. Nothing is sent on page load; nothing is sent without the click.
What is sent to the AI provider. The engine version and status (a reference-backed engine built on lunar-typescript 1.8.6, MIT), whether the hour pillar is present, each pillar's stem and branch (Chinese character, pinyin, element, polarity), the day-master stem (Chinese character, pinyin, element, polarity), the five-element counts and total, and the engine's fixed calculation warnings and method limitations.
What is never sent to the AI provider. Your raw birth date, birth time, birth city, name, email, free-text input, URL query, and any contents of localStorage, sessionStorage, IndexedDB, or the Cache API. The chart'sinput field is dropped before the payload is built. The server re-validates every field against the same strict allowlist and rejects unknown or out-of-range values.
Logs. Ordinary application logs on our side do not intentionally store the prompt or the AI response text, and the API key is never written to logs or returned in error responses. The server enforces a per-instance request budget as a best-effort guard and aborts any single request that takes longer than 35 seconds.
Consent model
Consent is strict opt-in. The first time you visit, a dialog asks you to choose Essential only or Allow analytics and replay. Until you choose, no Google Analytics script is loaded, no Microsoft Clarity script is loaded, no third-party request is made, and no event is sent. Your choice is stored only in this browser's localStorage under bazitrace.analytics.consent.v2; we do not store it on a server.
Versioning. The v2 consent also authorises Microsoft Clarity session replay. A prior v1 choice stored under bazitrace.analytics.consent.v1is migrated as follows: a v1 granted is treated as unset because v1 did not cover replay — the dialog re-prompts; a v1 denied is honoured as denied so the dialog does not re-appear on every page load. The v1 key is cleared once v2 takes over.
Pressing Esc or clicking outside the dialog is treated as the equivalent of Essential only. Nothing is sent to Google or Microsoft as a result of these actions.
Google as a data processor
When you allow analytics, Google processes technical identifiers (such as a randomised GA client id, IP address, browser version, and the events listed above) on its own infrastructure. Google may store or process this data outside your country. See Google's privacy policy for what Google does with that data.
Microsoft Clarity — what Microsoft records
When you allow analytics and replay, Microsoft Clarity loads its official asynchronous script. Microsoft processes technical metadata that its own documentation describes: the page URL (which Clarity captures itself — we do not control which query strings or hashes Microsoft may observe), the page referrer, the user agent string, the viewport size, the click and scroll positions, and the visible content of the page except for the masked regions listed below. Microsoft may store or process this data outside your country. See Microsoft's privacy statement and Microsoft Clarity's FAQ for what Microsoft does with that data.
What this site sends to Clarity. This site does not call Clarity's user-identification API, and it does not send your name, email, birth inputs, chart output, or AI explanation text as event tags. What this site does send is a small whitelist of low-cardinality category tags — language, calculator entry point, error type, and latency duration bucket — so the two vendors can be cross-referenced for legitimate session-replay QA. Microsoft's script automatically receives the page URL, the referrer URL, your IP address, and standard browser technical information as part of loading the SDK, in the same way it would for any third-party script.
What we cannot promise. Sensitive form inputs and the on-screen chart and AI interpretation regions are masked before any recording reaches Microsoft's servers, and birth information is not placed in the URL of this site. We do not, however, guarantee that the recording is fully anonymous: we cannot control what Microsoft's own infrastructure retains.
Masked regions on the chart page
Sensitive areas of the page are replaced with placeholders in the Clarity recording. The mask is applied to:
- The calculator form's date, time, city inputs and the "I do not know the time" checkbox.
- The chart page header that prints your birth date, time, and city back as a confirmation line.
- The day-master card, the four pillars grid, the pillar detail list, the five-element tally, the ten-gods and hidden-stems section, the three starting observations, the methodology detail when expanded, and the copy-chart-summary block.
- The AI interpretation region, including the typewriter-revealed output as it streams, the AI error notice, and the chart engine error notice.
Public navigation, buttons, and the consent dialog itself are not masked so you can still see and use them in the recording.
What replay does not promise
Microsoft Clarity session replay is best-effort. If you have an ad blocker, a strict network policy, or a browser that blocks third-party scripts, the Microsoft script may not load at all — even after you opt in. We do not guarantee that every session has a usable replay. We do not retroactively reconstruct sessions that you chose to block. If you deny consent before the script finishes loading, the script is stopped and the recording is halted once it has fully loaded.
Change or withdraw consent
You can change your choice at any time. Withdrawing saves your preference as Essential only / denied so the dialog does not reappear on every visit, stops future events from being sent, stops any active replay, and makes a best-effort attempt to delete cookies (_ga and the _ga_* family for Google; _clck, _clsk, and _cltk for Microsoft) that the vendor scripts wrote in your browser. Some vendor-side identifiers may remain because they are not always removable from JavaScript; this is an industry-wide limitation, not a BaziTrace choice. A late-loading script that arrives after you withdraw sees the denied consent and stop commands and continues to honour them.
We do not clear your stored preference when you deny — that would make the consent dialog reappear on every page load. The denied state is itself the record of your choice.
Language code, language switching, and low-cardinality failure categories
BaziTrace is now available in English, Indonesian (Bahasa Indonesia), and Brazilian Portuguese (Português do Brasil). The current page locale, the act of switching languages, and coarse failure categories are tallied as part of the analytics whitelist described above. The exact values are:
- content_language — one of
en,id,pt-BR. Recorded on every event that fires after consent, includingpage_context,calculator_start,calculator_submit,calculator_validation_error,chart_generated, AI events, and scroll/engagement milestones. - calculator_surface — one of
home,day_master,ten_gods. Tells the analytics report which calculator entry point the user came from. The default for the home calculators (/,/id,/pt-br) ishome; the dedicated/day-master-calculatorand/ten-gods-calculatortool pages useday_masterandten_godsrespectively. The tag is purely a low-cardinality entry-point identifier — it never includes birth data, four pillars, day master, element tally, or any chart content. - language_switch —
from_languageandto_language. Recorded once when you click a language in the header switcher. The two values are the same enum ascontent_language; nothing else is recorded. - calculator_validation_error —
error_typeis one ofmissing_date,invalid_date,missing_time,invalid_time,calculation,unknown. The error MESSAGE you see is local-only; only the coarse category reaches Google.
None of these events contain birth information. The calculator form never reads birth date, time, city, or any derived chart fields into the analytics payload. The same deny-by-default validator described above also applies to these new events.
Page context and the schema version
Most GA4 custom events this site dispatches carry three extra fields alongside the event-specific parameters listed above:
- schema_version — currently
4. A numeric marker stamped onto every queued event so the production report can pivot by the contract version. Bumping this number requires a code change. - page_id — the route pathname with the query string and hash stripped, sanitised against a small allow-list (
/,/sample,/chart,/privacy, …). Unknown paths becomeotherso the report stays low-cardinality. - page_type — the small enum (
home,sample,how_to_read,no_birth_time,methodology,learn,tool,privacy,terms,chart,not_found) the wrapper derives from the route.
Honest scope. The very first analytics_consent event on a fresh visit may fire before the router has resolved the current route, so it can carry schema_version but no page_id or page_type. Every event that fires after that — funnel steps, scroll, print, FAQ, AI events — carries the full trio.
Internal testing markers
Two URL flags exist purely so the team can validate analytics without polluting real visitor counts:
?bt_test=1— disables analytics and replay for the test tab, including subsequent page links and reloads when browser storage is available. A single local exclusion flag insessionStoragepreserves this choice for the tab’s browsing session; no URL, referrer, or birth data is stored in it. If storage is blocked, exclusion applies to the current page session only. No GA4 or Clarity script is loaded and no analytics event is queued while exclusion is active. Do not use this marker on a visit you want counted.?bt_debug=1— marks every dispatched event withdebug_mode: trueso it surfaces in GA4's DebugView. The marker is purely a tag: it does not route the event out of the production report on its own, and numbers observed while this flag is on are not business outcomes. Use it together withbt_test=1if you also want to keep test runs out of the count.
Sessions whose document.referrer comes from tagassistant.google.com are also suppressed. The client-side guard is best-effort; treat the analytics counts as a lower bound on real visitors, not an exact count.
Your controls
- Use the Manage analytics button in the footer to re-open the consent dialog.
- Use the Manage analytics settings button on this page for the same.
- Clear your browser's storage for
bazitrace.comto reset the consent prompt (the choice is the only thing stored in localStorage). - Refresh or close the tab to clear the current chart input.
- Use a private browsing window if you do not want the browser to retain a history entry.
- Close the tab when you finish on a shared device.
Honest scope
This page describes what BaziTrace's code does. It is not a legal compliance certification. If you need legal advice about GDPR, CCPA, or other privacy regulations, talk to a lawyer. We have not had this policy audited by an independent legal reviewer.
Last updated 2026-10-21. Substantive changes will be listed at the top of this page for at least 30 days. The 2026-10-06 update rewrites the Microsoft Clarity section to describe, in plain terms, what this site sends as event tags, what Microsoft automatically receives as part of loading the SDK, and what is not promised about the recording. The same update introduces schema_version 4: three new analytics events (calculator_submit_attempt, calculator_field_complete,chart_summary_copy), automatic schema_version /page_id / page_type stamping on dispatched GA4 custom events, and the internal ?bt_debug=1 marker documented above. Birth data, chart content, and AI text continue to be excluded from our analytics and replay event tags.