Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions .github/workflows/docs-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
name: Docs CI

on:
pull_request:
branches:
- main
push:
branches:
- main

concurrency:
group: docs-ci-${{ github.ref }}
cancel-in-progress: true

jobs:
checks:
name: Docs checks
runs-on: ubuntu-latest
timeout-minutes: 5
permissions:
contents: read
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
with:
python-version: "3.12"
- name: Install OpenAPI validator
run: pip install --quiet pyyaml openapi-spec-validator
# continue-on-error is deliberately absent: each check is a hard gate.
# Steps run in order and the job reports the first failure.
- name: Check frontmatter
run: python scripts/check_frontmatter.py
- name: Check code samples
if: '!cancelled()'
run: python scripts/check_code_samples.py
- name: Check internal links
if: '!cancelled()'
run: python scripts/check_links.py
- name: Check redirects
if: '!cancelled()'
run: python scripts/check_redirects.py
- name: Check OpenAPI specs
if: '!cancelled()'
run: python scripts/check_openapi.py
74 changes: 37 additions & 37 deletions docs.json
Original file line number Diff line number Diff line change
Expand Up @@ -409,7 +409,7 @@
"docs/data-governance/data-volume-monitoring",
"docs/data-governance/warehouse-sync-monitoring",
"docs/data-governance/data-clean-up",
"docs/data-governance/ai-powered-data-governance"
"docs/data-governance/ai-powered-data-governance"
]
},
{
Expand Down Expand Up @@ -705,7 +705,7 @@
"guides/strategic-playbooks/product-analytics-strategy/finale"
]
},
"guides/strategic-playbooks/onboarding-playbook",
"guides/strategic-playbooks/onboarding-playbook",
"guides/strategic-playbooks/project-migration",
"guides/strategic-playbooks/feature-flag-migration-playbook"
]
Expand Down Expand Up @@ -1879,7 +1879,7 @@
},
{
"source": "/docs/formulas",
"destination": "/changelogs/2023-09-19-formulas"
"destination": "/changelogs"
},
{
"source": "/docs/funnels",
Expand Down Expand Up @@ -2383,7 +2383,7 @@
},
{
"source": "/docs/tracking/data-warehouse/groups",
"destination": "/docs/tracking-methods/data-warehouse/sending-group-profiles"
"destination": "/docs/tracking-methods/warehouse-connectors"
},
{
"source": "/docs/tracking/data-warehouse/redshift",
Expand Down Expand Up @@ -2747,27 +2747,27 @@
},
{
"source": "/guides/plan/setup",
"destination": "/guides/strategic-playbooks/onboarding-playbook/plan/setup"
"destination": "/guides/strategic-playbooks/onboarding-playbook"
},
{
"source": "/guides/plan/framework",
"destination": "/guides/strategic-playbooks/onboarding-playbook/plan/framework"
"destination": "/guides/strategic-playbooks/onboarding-playbook"
},
{
"source": "/guides/plan/tracking-strategy",
"destination": "/guides/strategic-playbooks/onboarding-playbook/plan/tracking-strategy"
"destination": "/guides/strategic-playbooks/onboarding-playbook"
},
{
"source": "/guides/implement/send-your-data",
"destination": "/guides/strategic-playbooks/onboarding-playbook/implement/send-your-data"
"destination": "/guides/strategic-playbooks/onboarding-playbook"
},
{
"source": "/guides/implement/qa-data-audit",
"destination": "/guides/strategic-playbooks/onboarding-playbook/implement/qa-data-audit"
"destination": "/guides/strategic-playbooks/onboarding-playbook"
},
{
"source": "/guides/implement/establish-governance",
"destination": "/guides/strategic-playbooks/onboarding-playbook/implement/establish-governance"
"destination": "/guides/strategic-playbooks/onboarding-playbook"
},
{
"source": "/guides/launch/create-boards",
Expand Down Expand Up @@ -2855,7 +2855,7 @@
},
{
"source": "/hc",
"destination": "docs/getting-started/what-is-mixpanel"
"destination": "/docs/what-is-mixpanel"
},
{
"source": "/hc/admin/general_settings",
Expand Down Expand Up @@ -3227,71 +3227,71 @@
},
{
"source": "/hc/en-us/articles/13174988269844*",
"destination": "/changelogs/2022-12-01-improvements"
"destination": "/changelogs"
},
{
"source": "/hc/en-us/articles/13175102961428*",
"destination": "/changelogs/2022-12-13-boards"
"destination": "/changelogs"
},
{
"source": "/hc/en-us/articles/13175146659732*",
"destination": "/changelogs/2023-01-18-table-boards"
"destination": "/changelogs"
},
{
"source": "/hc/en-us/articles/13175184938260*",
"destination": "/changelogs/2023-01-23-users-flows"
"destination": "/changelogs"
},
{
"source": "/hc/en-us/articles/13175224500628*",
"destination": "/changelogs/2023-01-31-embed"
"destination": "/changelogs"
},
{
"source": "/hc/en-us/articles/13271005313556*",
"destination": "/docs/reports/insights#table-chart"
},
{
"source": "/hc/en-us/articles/13395179786644*",
"destination": "/changelogs/2022-07-08-reorient"
"destination": "/changelogs"
},
{
"source": "/hc/en-us/articles/13395198918804*",
"destination": "/changelogs/2022-11-03-session-improvements"
"destination": "/changelogs"
},
{
"source": "/hc/en-us/articles/13395199893652*",
"destination": "/changelogs/2022-11-07-millisecond"
"destination": "/changelogs"
},
{
"source": "/hc/en-us/articles/13395205961236*",
"destination": "/changelogs/2022-07-01-view-users"
"destination": "/changelogs"
},
{
"source": "/hc/en-us/articles/13395233184916*",
"destination": "/changelogs/2022-06-16-faster-workflow"
"destination": "/changelogs"
},
{
"source": "/hc/en-us/articles/13395235568660*",
"destination": "/changelogs/2022-05-31-improve-conversion-flow"
"destination": "/changelogs"
},
{
"source": "/hc/en-us/articles/13395324158868*",
"destination": "/changelogs/2022-05-24-lexicon-context"
"destination": "/changelogs"
},
{
"source": "/hc/en-us/articles/13395325754772*",
"destination": "/changelogs/2022-04-18-relative-comparison"
"destination": "/changelogs"
},
{
"source": "/hc/en-us/articles/13395328448404*",
"destination": "/changelogs/2022-03-29-text-boards"
"destination": "/changelogs"
},
{
"source": "/hc/en-us/articles/13530857626132*",
"destination": "/docs/pricing"
},
{
"source": "/hc/en-us/articles/13756463065492*",
"destination": "/changelogs/2023-02-28-retention-calendar-interval"
"destination": "/changelogs"
},
{
"source": "/hc/en-us/articles/14202292561172*",
Expand Down Expand Up @@ -3635,7 +3635,7 @@
},
{
"source": "/hc/en-us/articles/360041995352*",
"destination": "/docs/tracking/how-tos/events-properties"
"destination": "/docs/data-structure/events-and-properties"
},
{
"source": "/hc/en-us/articles/360042412051*",
Expand Down Expand Up @@ -4719,43 +4719,43 @@
},
{
"source": "/guides/guides-by-topic/core-reports/create-boards",
"destination":"/guides/guides-by-topic/core-reports"
"destination": "/guides/guides-by-topic/core-reports"
},
{
"source": "/guides/guides-by-topic/core-reports/discover-insights",
"destination":"/guides/guides-by-topic/core-reports"
"destination": "/guides/guides-by-topic/core-reports"
},
{
"source": "/guides/guides-by-topic/core-reports/analyze-conversions",
"destination":"/guides/guides-by-topic/core-reports"
"destination": "/guides/guides-by-topic/core-reports"
},
{
"source": "/guides/guides-by-topic/core-reports/build-user-flows",
"destination":"/guides/guides-by-topic/core-reports"
"destination": "/guides/guides-by-topic/core-reports"
},
{
"source": "/guides/guides-by-topic/core-reports/track-user-retention",
"destination":"/guides/guides-by-topic/core-reports"
"destination": "/guides/guides-by-topic/core-reports"
},
{
"source": "/guides/guides-by-topic/core-reports/define-cohorts",
"destination":"/guides/guides-by-topic/core-reports"
"destination": "/guides/guides-by-topic/core-reports"
},
{
"source": "/guides/strategic-playbooks/onboarding-playbook/plan/*",
"destination":"/guides/strategic-playbooks/onboarding-playbook"
"destination": "/guides/strategic-playbooks/onboarding-playbook"
},
{
"source": "/guides/strategic-playbooks/onboarding-playbook/implement/*",
"destination":"/guides/strategic-playbooks/onboarding-playbook"
"destination": "/guides/strategic-playbooks/onboarding-playbook"
},
{
"source": "/guides/strategic-playbooks/onboarding-playbook/launch/*",
"destination":"/guides/strategic-playbooks/onboarding-playbook"
"destination": "/guides/strategic-playbooks/onboarding-playbook"
},
{
"source": "/guides/strategic-playbooks/onboarding-playbook/beyond-onboarding",
"destination":"/guides/strategic-playbooks/onboarding-playbook"
"destination": "/guides/strategic-playbooks/onboarding-playbook"
}
]
}
2 changes: 1 addition & 1 deletion docs/mcp.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ Any client that supports the MCP JSON config format, including Microsoft Copilot
**Beta.** Service account authentication for MCP is in beta. The interface may change.
</Warning>

[Service accounts](/reference/Mixpanel%20APIs/authentication/service-accounts) are non-human Mixpanel users designed for scripts, back-end services, and automated workflows. They authenticate via a static header — no browser-based login is required.
[Service accounts](/reference/service-accounts) are non-human Mixpanel users designed for scripts, back-end services, and automated workflows. They authenticate via a static header — no browser-based login is required.

Use service accounts when you need a headless MCP connection, such as CI/CD pipelines, automated agents, or shared team setups. The service account's project permissions apply: it can only access projects it has been added to.

Expand Down
2 changes: 1 addition & 1 deletion reference/event-deduplication.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ Only the four key event properties listed above are used for deduplication. Addi

Deduplication occurs when a subset of the event data (event name, distinct\_id, timestamp, \$insert\_id) is identical. Other event properties are not considered.

**Required [Event Object](/docs/data-model#anatomy-of-an-event) attributes**
**Required [Event Object](/docs/data-structure/events-and-properties) attributes**

<table align={["left","left","left"]}>
<thead>
Expand Down
83 changes: 83 additions & 0 deletions scripts/check_code_samples.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
#!/usr/bin/env python3
"""
CI gate: every fenced code block in MDX files must declare a language.

A fenced block opening looks like:
```python
```javascript
```bash

A block with no language identifier:
```

will cause this check to fail.

Excluded directories (same as other checks):
- snippets/
- openapi/
"""

import sys
import glob
import os
import re

EXCLUDED_DIRS = {"snippets", "openapi"}

def check_file(path: str, display: str) -> list[str]:
errors = []
with open(path, encoding="utf-8") as fh:
content = fh.read()

fence_len = 0 # 0 = outside a block; otherwise the opening fence's length
for lineno, line in enumerate(content.splitlines(), 1):
stripped = line.strip()
if not stripped.startswith("```"):
continue
ticks = len(stripped) - len(stripped.lstrip("`"))
rest = stripped[ticks:].strip()
if fence_len:
# Only a bare fence at least as long as the opener closes the block,
# so a ```python block nested inside ````mdx does not end it early.
if ticks >= fence_len and not rest:
fence_len = 0
continue
if not rest:
errors.append(
f"{display}:{lineno}: code block is missing a language identifier"
)
fence_len = ticks

return errors
Comment thread
greptile-apps[bot] marked this conversation as resolved.


def is_excluded(path: str) -> bool:
parts = path.replace(os.sep, "/").split("/")
return any(part in EXCLUDED_DIRS for part in parts)


def main() -> int:
root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
mdx_files = glob.glob(os.path.join(root, "**", "*.mdx"), recursive=True)

checked = 0
all_errors: list[str] = []
for path in sorted(mdx_files):
rel = os.path.relpath(path, root)
if is_excluded(rel):
continue
all_errors.extend(check_file(path, rel))
checked += 1

if all_errors:
print("Code-sample check FAILED:")
for err in all_errors:
print(f" {err}")
return 1

print(f"Code-sample check PASSED ({checked} files checked).")
return 0


if __name__ == "__main__":
sys.exit(main())
Loading
Loading