oss-clarity 0.1.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (118) hide show
  1. oss_clarity-0.1.2/.github/workflows/ci.yml +133 -0
  2. oss_clarity-0.1.2/.github/workflows/publish.yml +45 -0
  3. oss_clarity-0.1.2/.gitignore +28 -0
  4. oss_clarity-0.1.2/CHANGELOG.md +81 -0
  5. oss_clarity-0.1.2/LICENSE +21 -0
  6. oss_clarity-0.1.2/PKG-INFO +188 -0
  7. oss_clarity-0.1.2/README.md +150 -0
  8. oss_clarity-0.1.2/THIRD_PARTY_NOTICES.md +85 -0
  9. oss_clarity-0.1.2/docs/api.md +30 -0
  10. oss_clarity-0.1.2/docs/images/heatmap-clicks.png +0 -0
  11. oss_clarity-0.1.2/docs/images/heatmap-scroll.png +0 -0
  12. oss_clarity-0.1.2/docs/images/replay.png +0 -0
  13. oss_clarity-0.1.2/docs/jobs.md +59 -0
  14. oss_clarity-0.1.2/docs/settings.md +93 -0
  15. oss_clarity-0.1.2/docs/signals.md +64 -0
  16. oss_clarity-0.1.2/docs/storage.md +71 -0
  17. oss_clarity-0.1.2/docs/thresholds.md +76 -0
  18. oss_clarity-0.1.2/docs/upgrading.md +23 -0
  19. oss_clarity-0.1.2/example/README.md +26 -0
  20. oss_clarity-0.1.2/example/example_project/__init__.py +0 -0
  21. oss_clarity-0.1.2/example/example_project/management/__init__.py +0 -0
  22. oss_clarity-0.1.2/example/example_project/management/commands/__init__.py +0 -0
  23. oss_clarity-0.1.2/example/example_project/management/commands/example_site.py +19 -0
  24. oss_clarity-0.1.2/example/example_project/settings.py +81 -0
  25. oss_clarity-0.1.2/example/example_project/templates/page.html +38 -0
  26. oss_clarity-0.1.2/example/example_project/urls.py +19 -0
  27. oss_clarity-0.1.2/example/manage.py +9 -0
  28. oss_clarity-0.1.2/js/README.md +19 -0
  29. oss_clarity-0.1.2/js/package-lock.json +673 -0
  30. oss_clarity-0.1.2/js/package.json +21 -0
  31. oss_clarity-0.1.2/js/player/index.ts +569 -0
  32. oss_clarity-0.1.2/js/player/player.css +223 -0
  33. oss_clarity-0.1.2/js/recorder/build.mjs +84 -0
  34. oss_clarity-0.1.2/js/recorder/index.ts +536 -0
  35. oss_clarity-0.1.2/js/tests/recorder.test.mjs +191 -0
  36. oss_clarity-0.1.2/js/tsconfig.json +12 -0
  37. oss_clarity-0.1.2/js/types.d.ts +1 -0
  38. oss_clarity-0.1.2/pyproject.toml +73 -0
  39. oss_clarity-0.1.2/src/oss_clarity/__init__.py +6 -0
  40. oss_clarity-0.1.2/src/oss_clarity/admin.py +346 -0
  41. oss_clarity-0.1.2/src/oss_clarity/analysis.py +154 -0
  42. oss_clarity-0.1.2/src/oss_clarity/apps.py +20 -0
  43. oss_clarity-0.1.2/src/oss_clarity/choices.py +81 -0
  44. oss_clarity-0.1.2/src/oss_clarity/collect.py +207 -0
  45. oss_clarity-0.1.2/src/oss_clarity/conf.py +173 -0
  46. oss_clarity-0.1.2/src/oss_clarity/core/__init__.py +25 -0
  47. oss_clarity-0.1.2/src/oss_clarity/core/events.py +43 -0
  48. oss_clarity-0.1.2/src/oss_clarity/core/measure.py +211 -0
  49. oss_clarity-0.1.2/src/oss_clarity/core/mirror.py +315 -0
  50. oss_clarity-0.1.2/src/oss_clarity/core/navigation.py +90 -0
  51. oss_clarity-0.1.2/src/oss_clarity/core/sampling.py +34 -0
  52. oss_clarity-0.1.2/src/oss_clarity/core/signals.py +595 -0
  53. oss_clarity-0.1.2/src/oss_clarity/core/thresholds.py +63 -0
  54. oss_clarity-0.1.2/src/oss_clarity/core/useragent.py +86 -0
  55. oss_clarity-0.1.2/src/oss_clarity/heatmaps.py +309 -0
  56. oss_clarity-0.1.2/src/oss_clarity/jobs.py +119 -0
  57. oss_clarity-0.1.2/src/oss_clarity/management/__init__.py +0 -0
  58. oss_clarity-0.1.2/src/oss_clarity/management/commands/__init__.py +0 -0
  59. oss_clarity-0.1.2/src/oss_clarity/management/commands/oss_clarity_erase_visitor.py +37 -0
  60. oss_clarity-0.1.2/src/oss_clarity/management/commands/oss_clarity_measure.py +134 -0
  61. oss_clarity-0.1.2/src/oss_clarity/management/commands/oss_clarity_prune.py +14 -0
  62. oss_clarity-0.1.2/src/oss_clarity/management/commands/oss_clarity_run_jobs.py +46 -0
  63. oss_clarity-0.1.2/src/oss_clarity/middleware.py +54 -0
  64. oss_clarity-0.1.2/src/oss_clarity/migrations/0001_initial.py +288 -0
  65. oss_clarity-0.1.2/src/oss_clarity/migrations/__init__.py +0 -0
  66. oss_clarity-0.1.2/src/oss_clarity/models.py +437 -0
  67. oss_clarity-0.1.2/src/oss_clarity/reading.py +182 -0
  68. oss_clarity-0.1.2/src/oss_clarity/record.py +318 -0
  69. oss_clarity-0.1.2/src/oss_clarity/retention.py +144 -0
  70. oss_clarity-0.1.2/src/oss_clarity/static/oss_clarity/player.css +2 -0
  71. oss_clarity-0.1.2/src/oss_clarity/static/oss_clarity/player.js +130 -0
  72. oss_clarity-0.1.2/src/oss_clarity/static/oss_clarity/recorder.js +79 -0
  73. oss_clarity-0.1.2/src/oss_clarity/storage.py +83 -0
  74. oss_clarity-0.1.2/src/oss_clarity/tasks.py +64 -0
  75. oss_clarity-0.1.2/src/oss_clarity/templates/admin/oss_clarity/recording/change_form.html +13 -0
  76. oss_clarity-0.1.2/src/oss_clarity/templates/admin/oss_clarity/site/change_form.html +6 -0
  77. oss_clarity-0.1.2/src/oss_clarity/templates/admin/oss_clarity/site/heatmap.html +61 -0
  78. oss_clarity-0.1.2/src/oss_clarity/throttle.py +127 -0
  79. oss_clarity-0.1.2/src/oss_clarity/tracker.py +547 -0
  80. oss_clarity-0.1.2/src/oss_clarity/urls/__init__.py +1 -0
  81. oss_clarity-0.1.2/src/oss_clarity/urls/api.py +25 -0
  82. oss_clarity-0.1.2/src/oss_clarity/urls/converters.py +24 -0
  83. oss_clarity-0.1.2/src/oss_clarity/urls/public.py +26 -0
  84. oss_clarity-0.1.2/src/oss_clarity/views/__init__.py +0 -0
  85. oss_clarity-0.1.2/src/oss_clarity/views/api.py +134 -0
  86. oss_clarity-0.1.2/src/oss_clarity/views/public.py +226 -0
  87. oss_clarity-0.1.2/tests/__init__.py +0 -0
  88. oss_clarity-0.1.2/tests/conftest.py +4 -0
  89. oss_clarity-0.1.2/tests/core/__init__.py +0 -0
  90. oss_clarity-0.1.2/tests/core/stream.py +143 -0
  91. oss_clarity-0.1.2/tests/core/test_docs.py +21 -0
  92. oss_clarity-0.1.2/tests/core/test_measure.py +106 -0
  93. oss_clarity-0.1.2/tests/core/test_navigation.py +80 -0
  94. oss_clarity-0.1.2/tests/core/test_no_django.py +37 -0
  95. oss_clarity-0.1.2/tests/core/test_sampling.py +66 -0
  96. oss_clarity-0.1.2/tests/core/test_signals.py +474 -0
  97. oss_clarity-0.1.2/tests/core/test_useragent.py +75 -0
  98. oss_clarity-0.1.2/tests/django/__init__.py +0 -0
  99. oss_clarity-0.1.2/tests/django/conftest.py +76 -0
  100. oss_clarity-0.1.2/tests/django/middleware.py +11 -0
  101. oss_clarity-0.1.2/tests/django/settings.py +68 -0
  102. oss_clarity-0.1.2/tests/django/test_admin.py +167 -0
  103. oss_clarity-0.1.2/tests/django/test_analysis.py +164 -0
  104. oss_clarity-0.1.2/tests/django/test_api.py +176 -0
  105. oss_clarity-0.1.2/tests/django/test_collect.py +312 -0
  106. oss_clarity-0.1.2/tests/django/test_conf.py +72 -0
  107. oss_clarity-0.1.2/tests/django/test_docs.py +13 -0
  108. oss_clarity-0.1.2/tests/django/test_heatmaps.py +91 -0
  109. oss_clarity-0.1.2/tests/django/test_jobs.py +165 -0
  110. oss_clarity-0.1.2/tests/django/test_measure_command.py +50 -0
  111. oss_clarity-0.1.2/tests/django/test_models.py +90 -0
  112. oss_clarity-0.1.2/tests/django/test_record.py +269 -0
  113. oss_clarity-0.1.2/tests/django/test_retention.py +207 -0
  114. oss_clarity-0.1.2/tests/django/test_throttle.py +134 -0
  115. oss_clarity-0.1.2/tests/django/test_tracker.py +243 -0
  116. oss_clarity-0.1.2/tests/django/urls.py +8 -0
  117. oss_clarity-0.1.2/tests/django/urls_admin_only.py +4 -0
  118. oss_clarity-0.1.2/tests/vectors/sampling.json +50 -0
@@ -0,0 +1,133 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+
8
+ permissions:
9
+ contents: read
10
+
11
+ concurrency:
12
+ group: ci-${{ github.ref }}
13
+ cancel-in-progress: true
14
+
15
+ jobs:
16
+ lint:
17
+ runs-on: ubuntu-latest
18
+ steps:
19
+ - uses: actions/checkout@v4
20
+ - uses: actions/setup-python@v5
21
+ with:
22
+ python-version: "3.13"
23
+ - run: pip install "ruff>=0.6"
24
+ - run: ruff check .
25
+ - run: ruff format --check .
26
+
27
+ # The core library must install and pass its tests with Django absent.
28
+ core:
29
+ runs-on: ubuntu-latest
30
+ strategy:
31
+ fail-fast: false
32
+ matrix:
33
+ python: ["3.11", "3.14"]
34
+ steps:
35
+ - uses: actions/checkout@v4
36
+ - uses: actions/setup-python@v5
37
+ with:
38
+ python-version: ${{ matrix.python }}
39
+ - run: pip install -e . pytest
40
+ - name: Django is not installed
41
+ run: python -c "import importlib.util, sys; sys.exit(importlib.util.find_spec('django') is not None)"
42
+ - run: pytest -q
43
+
44
+ django:
45
+ runs-on: ubuntu-latest
46
+ strategy:
47
+ fail-fast: false
48
+ matrix:
49
+ include:
50
+ - { django: "5.2", python: "3.11", db: sqlite }
51
+ - { django: "5.2", python: "3.12", db: sqlite }
52
+ - { django: "5.2", python: "3.13", db: sqlite }
53
+ - { django: "5.2", python: "3.14", db: sqlite }
54
+ - { django: "5.2", python: "3.14", db: postgres }
55
+ - { django: "6.0", python: "3.12", db: sqlite }
56
+ - { django: "6.0", python: "3.13", db: sqlite }
57
+ - { django: "6.0", python: "3.14", db: sqlite }
58
+ - { django: "6.0", python: "3.14", db: postgres }
59
+ - { django: "6.1", python: "3.12", db: sqlite }
60
+ - { django: "6.1", python: "3.13", db: sqlite }
61
+ - { django: "6.1", python: "3.14", db: sqlite }
62
+ - { django: "6.1", python: "3.14", db: postgres }
63
+ services:
64
+ postgres:
65
+ image: postgres:17
66
+ env:
67
+ POSTGRES_USER: oc
68
+ POSTGRES_PASSWORD: oc
69
+ POSTGRES_DB: oc
70
+ ports: ["5432:5432"]
71
+ options: >-
72
+ --health-cmd pg_isready --health-interval 5s --health-timeout 5s --health-retries 10
73
+ env:
74
+ DATABASE_URL: ${{ matrix.db == 'postgres' && 'postgres://oc:oc@localhost:5432/oc' || '' }}
75
+ steps:
76
+ - uses: actions/checkout@v4
77
+ - uses: actions/setup-python@v5
78
+ with:
79
+ python-version: ${{ matrix.python }}
80
+ # The tracker tests run the served tracker in Node.
81
+ - uses: actions/setup-node@v4
82
+ with:
83
+ node-version: "24"
84
+ - run: pip install -e ".[django,celery]" "Django~=${{ matrix.django }}.0" pytest pytest-django
85
+ - if: matrix.db == 'postgres'
86
+ run: pip install "psycopg[binary]>=3.2"
87
+ - run: python -m django --version
88
+ - run: pytest -q
89
+ - name: The example project passes its checks
90
+ working-directory: example
91
+ run: python manage.py check
92
+ - name: Migrations match the models
93
+ run: >-
94
+ PYTHONPATH=. DJANGO_SETTINGS_MODULE=tests.django.settings
95
+ django-admin makemigrations oss_clarity --check --dry-run
96
+
97
+ # The committed bundles must be exactly what the lockfile builds.
98
+ js:
99
+ runs-on: ubuntu-latest
100
+ defaults:
101
+ run:
102
+ working-directory: js
103
+ steps:
104
+ - uses: actions/checkout@v4
105
+ - uses: actions/setup-node@v4
106
+ with:
107
+ node-version: "24"
108
+ cache: npm
109
+ cache-dependency-path: js/package-lock.json
110
+ - run: npm ci
111
+ - run: npm run typecheck
112
+ - run: npm test
113
+ - run: npm run build
114
+ - name: Committed bundles match a fresh build
115
+ run: git diff --exit-code -- ../src/oss_clarity/static
116
+
117
+ package:
118
+ runs-on: ubuntu-latest
119
+ steps:
120
+ - uses: actions/checkout@v4
121
+ - uses: actions/setup-python@v5
122
+ with:
123
+ python-version: "3.13"
124
+ - run: pip install build
125
+ - run: python -m build
126
+ - name: The wheel carries the bundles, migrations, templates and notices
127
+ run: |
128
+ unzip -l dist/*.whl > contents.txt
129
+ for f in static/oss_clarity/recorder.js static/oss_clarity/player.js \
130
+ static/oss_clarity/player.css migrations/0001_initial.py \
131
+ templates/admin/oss_clarity/site/heatmap.html THIRD_PARTY_NOTICES.md; do
132
+ grep -q "$f" contents.txt || { echo "missing from wheel: $f"; exit 1; }
133
+ done
@@ -0,0 +1,45 @@
1
+ name: Publish
2
+
3
+ # Pushing a version tag (v0.1.2) builds the release and uploads it to PyPI through a
4
+ # trusted publisher: no API token is stored anywhere.
5
+ on:
6
+ push:
7
+ tags: ["v*"]
8
+
9
+ permissions:
10
+ contents: read
11
+
12
+ jobs:
13
+ build:
14
+ runs-on: ubuntu-latest
15
+ steps:
16
+ - uses: actions/checkout@v4
17
+ - uses: actions/setup-python@v5
18
+ with:
19
+ python-version: "3.13"
20
+ - name: The tag matches the package version
21
+ run: |
22
+ version=$(python -c "import re; print(re.search(r'__version__ = \"(.+)\"', open('src/oss_clarity/__init__.py').read())[1])")
23
+ [ "v$version" = "$GITHUB_REF_NAME" ] || { echo "tag $GITHUB_REF_NAME, version $version"; exit 1; }
24
+ - run: pip install build
25
+ - run: python -m build
26
+ - uses: actions/upload-artifact@v4
27
+ with:
28
+ name: dist
29
+ path: dist/
30
+
31
+ publish:
32
+ needs: build
33
+ runs-on: ubuntu-latest
34
+ # Must match the environment on the PyPI trusted publisher.
35
+ environment:
36
+ name: pypi
37
+ url: https://pypi.org/p/oss-clarity
38
+ permissions:
39
+ id-token: write
40
+ steps:
41
+ - uses: actions/download-artifact@v4
42
+ with:
43
+ name: dist
44
+ path: dist/
45
+ - uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,28 @@
1
+ # Private build brief — never committed.
2
+ PLAN.md
3
+
4
+ # Python
5
+ __pycache__/
6
+ *.py[cod]
7
+ *.egg-info/
8
+ .venv/
9
+ venv/
10
+ build/
11
+ dist/
12
+ .pytest_cache/
13
+ .ruff_cache/
14
+ .coverage
15
+ htmlcov/
16
+
17
+ # JS
18
+ node_modules/
19
+
20
+ # Editors and OS
21
+ .idea/
22
+ .vscode/
23
+ .DS_Store
24
+
25
+ # Example project
26
+ example/db.sqlite3
27
+ example/media/
28
+ example/.cache/
@@ -0,0 +1,81 @@
1
+ # Changelog
2
+
3
+ ## 0.1.2 — 2026-09-27
4
+
5
+ First release on PyPI.
6
+
7
+ Changed
8
+
9
+ - The README installs from PyPI, and its links and images point at the v0.1.2 tag on GitHub,
10
+ so they work on the PyPI project page.
11
+
12
+ ## 0.1.1 — 2026-09-26
13
+
14
+ Fixed
15
+
16
+ - The recorder lost the events buffered when a page was hidden or closed: it compressed
17
+ the last chunk before sending it, and a page going away gets no further turn for the
18
+ compression to finish. Up to five seconds at the end of every page were missing, and a
19
+ page left within five seconds of loading was missing from its recording altogether. The
20
+ recorder now sends as soon as the page is hidden or closed, uncompressed, in parts that fit
21
+ the browser's 64 KB keepalive budget. Chunks sent while the page stays open are still
22
+ gzipped. The recorder's URL carries a new digest, so browsers fetch the fixed bundle.
23
+ - The example page sets its own background, so it stays readable when the browser prefers a
24
+ dark colour scheme.
25
+
26
+ Added
27
+
28
+ - `npm test` in `js/`: the recorder's uploads, run in Node with rrweb stubbed out. CI runs it.
29
+
30
+ ## 0.1.0 — 2026-09-26
31
+
32
+ First release.
33
+
34
+ - `oss_clarity.core`: rules-based signal analysis of rrweb recordings (`analyze`), frozen
35
+ `Thresholds`, quick backs and loops from page views (`navigation`), a user-agent classifier
36
+ with a bot test, and a threshold measuring tool (`measure`). No Django required.
37
+ - Django app `oss_clarity`: models for sites, recording settings, hits, recordings and their
38
+ chunks, heatmap buckets, visit navigation and job runs, in one initial migration. No IP
39
+ address or raw user agent is stored.
40
+ - `OSS_CLARITY` settings dict with defaults for every key, checked by `manage.py check`.
41
+ - Admin: sites with their recording settings and refusal counters, read-only hits, recordings
42
+ filterable by signal, favourites, and job runs.
43
+ - Public collector (`oss_clarity.urls.public`): the tracker script per site, the recorder
44
+ bundle under a content digest, page views, clicks and page leaves, and recording chunks
45
+ (gzip accepted). Host allow-list, crawler refusal for recordings, sampling by session-id
46
+ hash, size and session caps, and per-address, per-site and global rate limits. Every
47
+ refusal answers 204.
48
+ - Client IP for rate limits resolved by `TRUSTED_PROXY_COUNT`, `CLIENT_IP_HEADER` or
49
+ `CLIENT_IP_FUNCTION`; used in memory only.
50
+ - The tracker honours Global Privacy Control for recording, supports a consent gate, and
51
+ exposes `ossClarity("visitorId")` and `ossClarity("forget")`. Clicks carry position and a
52
+ selector only; credential-shaped query values are redacted before any URL is stored.
53
+ - Recorder bundle built from `js/recorder` with esbuild; third-party notices in
54
+ `THIRD_PARTY_NOTICES.md`.
55
+ - Optional `PublicEndpointsMiddleware` for hosts whose CORS or cache middleware would
56
+ override the public endpoints' headers.
57
+ - Background jobs in `oss_clarity.jobs`: finalize and analyse quiet recordings, store visits'
58
+ quick backs and loops, roll up heatmaps per UTC day, and prune by retention window. Each
59
+ run is claimed in `JobRun` with one conditional update, so overlapping runs never repeat
60
+ a job. Run them with `manage.py oss_clarity_run_jobs` from cron, or the optional Celery
61
+ tasks and `BEAT_SCHEDULE` in `oss_clarity.tasks`.
62
+ - Visitor erasure: `retention.erase_visitor`, `manage.py oss_clarity_erase_visitor` and an
63
+ admin action. Stored chunks are always deleted before rows; a failed delete keeps the rows
64
+ for the next run.
65
+ - `manage.py oss_clarity_measure` reports how many signals each threshold setting would
66
+ find, with moments to watch. It writes nothing.
67
+ - Recordings can be deleted from the admin, stored chunks first.
68
+ - Read-only JSON API (`oss_clarity.urls.api`): recordings filterable by any-of signals and
69
+ favourites, one recording with its pages, a page's events, heatmap pages, one heatmap,
70
+ and sessions with quick backs and loops on every row. Staff only unless
71
+ `API_PERMISSION` says otherwise.
72
+ - Admin viewer: a replay on each recording's page, with signals on the timeline and as a
73
+ list, and a heatmap page per site (page, device and range pickers; click and scroll-depth
74
+ maps drawn over the newest recorded snapshot of that page). Built from `js/player` on
75
+ rrweb's replayer, sandboxed without scripts.
76
+ - The replay strips inline event handlers from recorded pages, and the heatmap
77
+ measures the rebuilt page only after it has been laid out.
78
+ - Documentation (`docs/`), a README with the privacy stance, an example project, and CI
79
+ for lint, the core without Django, the Django × Python matrix on SQLite and PostgreSQL,
80
+ bundle reproducibility and the wheel's contents.
81
+
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Meharaj Ul Mahmmud
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,188 @@
1
+ Metadata-Version: 2.5
2
+ Name: oss-clarity
3
+ Version: 0.1.2
4
+ Summary: Self-hosted session replay, heatmaps and rules-based behaviour signals for Django
5
+ Project-URL: Homepage, https://github.com/meharaj-007/oss-clarity
6
+ Project-URL: Documentation, https://github.com/meharaj-007/oss-clarity/tree/main/docs
7
+ Project-URL: Changelog, https://github.com/meharaj-007/oss-clarity/blob/main/CHANGELOG.md
8
+ Author: Meharaj Ul Mahmmud
9
+ License-Expression: MIT
10
+ License-File: LICENSE
11
+ License-File: THIRD_PARTY_NOTICES.md
12
+ Keywords: analytics,django,heatmaps,privacy,rrweb,session-replay
13
+ Classifier: Development Status :: 2 - Pre-Alpha
14
+ Classifier: Framework :: Django
15
+ Classifier: Framework :: Django :: 5.2
16
+ Classifier: Framework :: Django :: 6.0
17
+ Classifier: Framework :: Django :: 6.1
18
+ Classifier: Programming Language :: Python :: 3
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Programming Language :: Python :: 3.13
22
+ Classifier: Programming Language :: Python :: 3.14
23
+ Requires-Python: >=3.11
24
+ Provides-Extra: celery
25
+ Requires-Dist: celery>=5.3; extra == 'celery'
26
+ Provides-Extra: dev
27
+ Requires-Dist: build>=1; extra == 'dev'
28
+ Requires-Dist: celery>=5.3; extra == 'dev'
29
+ Requires-Dist: pytest-django>=4.9; extra == 'dev'
30
+ Requires-Dist: pytest>=8; extra == 'dev'
31
+ Requires-Dist: ruff>=0.6; extra == 'dev'
32
+ Provides-Extra: django
33
+ Requires-Dist: django>=5.2; extra == 'django'
34
+ Requires-Dist: rjsmin>=1.2; extra == 'django'
35
+ Provides-Extra: s3
36
+ Requires-Dist: django-storages[s3]>=1.14; extra == 's3'
37
+ Description-Content-Type: text/markdown
38
+
39
+ # oss-clarity
40
+
41
+ Self-hosted session replay, heatmaps and rules-based behaviour signals for Django.
42
+
43
+ Add one script tag to your site. oss-clarity counts page views, clicks and scroll
44
+ depth, records sampled visits with [rrweb](https://github.com/rrweb-io/rrweb), and
45
+ marks where people struggled: rage clicks, dead clicks, hesitations, form
46
+ abandons and more. You watch the replays and heatmaps in your Django admin. Every
47
+ byte stays on your servers.
48
+
49
+ > Early release (0.1.2).
50
+ > Settings and the JSON API may still change.
51
+
52
+ ![A replay in the Django admin, with signals on the timeline](https://raw.githubusercontent.com/meharaj-007/oss-clarity/v0.1.2/docs/images/replay.png)
53
+
54
+ ## What you get
55
+
56
+ - **Tracking**: page views (including single-page-app route changes), clicks with
57
+ their position, and how far each page was scrolled. About 10 KB of JavaScript
58
+ (4 KB gzipped), reporting after the page loads, with no cookies.
59
+ - **Recording**: sampled session replay, masked in the visitor's browser before
60
+ anything is sent. Capped per visit by size, pages and minutes.
61
+ - **Signals**: 15 rules, each a documented, deterministic check with named
62
+ thresholds, and a tool to measure those thresholds against your own recordings.
63
+ See [signals](https://github.com/meharaj-007/oss-clarity/blob/v0.1.2/docs/signals.md).
64
+ - **Heatmaps**: clicks and scroll depth per page and device, drawn over a recorded
65
+ snapshot of the page.
66
+ - **Viewer**: replay and heatmap pages inside Django admin, and a read-only
67
+ [JSON API](https://github.com/meharaj-007/oss-clarity/blob/v0.1.2/docs/api.md).
68
+
69
+ ![Clicks on a page, drawn over a recorded snapshot](https://raw.githubusercontent.com/meharaj-007/oss-clarity/v0.1.2/docs/images/heatmap-clicks.png)
70
+
71
+ ## Privacy
72
+
73
+ - **No AI.** Signals are plain rules you can read. Recordings are never sent to
74
+ any third party or model.
75
+ - **Masked by default.** Form fields are masked in every mode and cannot be
76
+ unmasked. The default mode also blanks digits and email addresses, and `data:`
77
+ and `blob:` images (a photo a visitor just picked, say) are never recorded.
78
+ - **Global Privacy Control is honoured.** A browser that sends it is never
79
+ recorded; its page views are still counted.
80
+ - **Optional consent gate.** Per site, nothing is recorded until your page calls
81
+ `ossClarity("consent", true)`.
82
+ - **No IP addresses stored.** The address is used in memory for rate limits only.
83
+ Raw user agents are not stored either, only coarse device, browser and OS.
84
+ - **No text from clicks.** A click records where it landed and a selector for the
85
+ element, never the element's text or link. Password, token and similar values in
86
+ page URLs are replaced before storage.
87
+ - **Crawlers are not recorded.** Bots that run JavaScript are refused by the
88
+ tracker and again by the collector.
89
+ - **Erase on request.** `ossClarity("visitorId")` gives a visitor their id;
90
+ `manage.py oss_clarity_erase_visitor <id>` deletes everything held about them.
91
+ `ossClarity("forget")` clears the ids in their browser.
92
+ - **Retention.** Hits and recordings are deleted after 30 days by default.
93
+
94
+ ## Install
95
+
96
+ ```sh
97
+ pip install "oss-clarity[django]"
98
+ ```
99
+
100
+ Python 3.11 to 3.14, Django 5.2, 6.0 and 6.1, SQLite or PostgreSQL.
101
+
102
+ ## Set up
103
+
104
+ **1. Settings**
105
+
106
+ ```python
107
+ INSTALLED_APPS = [..., "oss_clarity"]
108
+
109
+ MIDDLEWARE = [
110
+ "oss_clarity.middleware.PublicEndpointsMiddleware", # first
111
+ ...,
112
+ ]
113
+ ```
114
+
115
+ The middleware is only needed if something else in your stack (django-cors-headers,
116
+ a no-store cache policy) would override the public endpoints' headers. It is safe
117
+ to always include. Every other setting has a default; see
118
+ [settings](https://github.com/meharaj-007/oss-clarity/blob/v0.1.2/docs/settings.md).
119
+
120
+ **2. URLs**
121
+
122
+ ```python
123
+ urlpatterns = [
124
+ ...,
125
+ path("oc/", include("oss_clarity.urls.public")), # tracker and collector
126
+ path("oc-api/", include("oss_clarity.urls.api")), # read-only API, optional
127
+ ]
128
+ ```
129
+
130
+ Then `python manage.py migrate`.
131
+
132
+ **3. Jobs**, every five minutes from cron (or use the
133
+ [Celery tasks](https://github.com/meharaj-007/oss-clarity/blob/v0.1.2/docs/jobs.md)):
134
+
135
+ ```cron
136
+ */5 * * * * cd /srv/app && python manage.py oss_clarity_run_jobs
137
+ ```
138
+
139
+ **4. The snippet.** Add a site in the admin (Session replay and heatmaps → Sites),
140
+ switch recording on in its recording settings if you want replays, and paste the
141
+ snippet it shows into your pages' `<head>`:
142
+
143
+ ```html
144
+ <script async src="https://your-app.example.com/oc/t/<site key>.js"></script>
145
+ ```
146
+
147
+ Visits appear as hits straight away. Recordings are analysed a few minutes after a
148
+ visit ends, and heatmaps update hourly.
149
+
150
+ To see it all working on your own machine first, run the
151
+ [example project](https://github.com/meharaj-007/oss-clarity/blob/v0.1.2/example/README.md).
152
+
153
+ ## Documentation
154
+
155
+ - [Signals](https://github.com/meharaj-007/oss-clarity/blob/v0.1.2/docs/signals.md): what each one means
156
+ - [Thresholds](https://github.com/meharaj-007/oss-clarity/blob/v0.1.2/docs/thresholds.md): the numbers, and how to measure them
157
+ - [Settings](https://github.com/meharaj-007/oss-clarity/blob/v0.1.2/docs/settings.md): every key
158
+ - [Storage](https://github.com/meharaj-007/oss-clarity/blob/v0.1.2/docs/storage.md): local disk or S3
159
+ - [Jobs](https://github.com/meharaj-007/oss-clarity/blob/v0.1.2/docs/jobs.md): cron or Celery
160
+ - [JSON API](https://github.com/meharaj-007/oss-clarity/blob/v0.1.2/docs/api.md)
161
+ - [Upgrading](https://github.com/meharaj-007/oss-clarity/blob/v0.1.2/docs/upgrading.md)
162
+
163
+ ## Limits
164
+
165
+ - One recording per visit, at most 10 MiB, 128 pages and 120 minutes by default.
166
+ - Replays load images, fonts and styles from your live site, so ones changed or
167
+ removed since render differently.
168
+ - Heatmaps group pages by path (query strings ignored, trailing slashes folded)
169
+ and by device class. Clicks are placed on the element when the snapshot still
170
+ has it, and by position otherwise.
171
+ - Automated browsers (`navigator.webdriver`, headless Chrome) are treated as
172
+ crawlers and never recorded.
173
+ - No multi-tenant accounts, billing or quotas: that is your project's business.
174
+
175
+ ## Development
176
+
177
+ ```sh
178
+ pip install -e ".[django,dev]"
179
+ pytest
180
+ ruff check . && ruff format --check .
181
+ cd js && npm ci && npm run typecheck && npm run build # rebuilds the committed bundles
182
+ ```
183
+
184
+ ## Licence
185
+
186
+ MIT. See [LICENSE](https://github.com/meharaj-007/oss-clarity/blob/v0.1.2/LICENSE).
187
+ The bundled rrweb and its dependencies are listed in
188
+ [THIRD_PARTY_NOTICES.md](https://github.com/meharaj-007/oss-clarity/blob/v0.1.2/THIRD_PARTY_NOTICES.md).
@@ -0,0 +1,150 @@
1
+ # oss-clarity
2
+
3
+ Self-hosted session replay, heatmaps and rules-based behaviour signals for Django.
4
+
5
+ Add one script tag to your site. oss-clarity counts page views, clicks and scroll
6
+ depth, records sampled visits with [rrweb](https://github.com/rrweb-io/rrweb), and
7
+ marks where people struggled: rage clicks, dead clicks, hesitations, form
8
+ abandons and more. You watch the replays and heatmaps in your Django admin. Every
9
+ byte stays on your servers.
10
+
11
+ > Early release (0.1.2).
12
+ > Settings and the JSON API may still change.
13
+
14
+ ![A replay in the Django admin, with signals on the timeline](https://raw.githubusercontent.com/meharaj-007/oss-clarity/v0.1.2/docs/images/replay.png)
15
+
16
+ ## What you get
17
+
18
+ - **Tracking**: page views (including single-page-app route changes), clicks with
19
+ their position, and how far each page was scrolled. About 10 KB of JavaScript
20
+ (4 KB gzipped), reporting after the page loads, with no cookies.
21
+ - **Recording**: sampled session replay, masked in the visitor's browser before
22
+ anything is sent. Capped per visit by size, pages and minutes.
23
+ - **Signals**: 15 rules, each a documented, deterministic check with named
24
+ thresholds, and a tool to measure those thresholds against your own recordings.
25
+ See [signals](https://github.com/meharaj-007/oss-clarity/blob/v0.1.2/docs/signals.md).
26
+ - **Heatmaps**: clicks and scroll depth per page and device, drawn over a recorded
27
+ snapshot of the page.
28
+ - **Viewer**: replay and heatmap pages inside Django admin, and a read-only
29
+ [JSON API](https://github.com/meharaj-007/oss-clarity/blob/v0.1.2/docs/api.md).
30
+
31
+ ![Clicks on a page, drawn over a recorded snapshot](https://raw.githubusercontent.com/meharaj-007/oss-clarity/v0.1.2/docs/images/heatmap-clicks.png)
32
+
33
+ ## Privacy
34
+
35
+ - **No AI.** Signals are plain rules you can read. Recordings are never sent to
36
+ any third party or model.
37
+ - **Masked by default.** Form fields are masked in every mode and cannot be
38
+ unmasked. The default mode also blanks digits and email addresses, and `data:`
39
+ and `blob:` images (a photo a visitor just picked, say) are never recorded.
40
+ - **Global Privacy Control is honoured.** A browser that sends it is never
41
+ recorded; its page views are still counted.
42
+ - **Optional consent gate.** Per site, nothing is recorded until your page calls
43
+ `ossClarity("consent", true)`.
44
+ - **No IP addresses stored.** The address is used in memory for rate limits only.
45
+ Raw user agents are not stored either, only coarse device, browser and OS.
46
+ - **No text from clicks.** A click records where it landed and a selector for the
47
+ element, never the element's text or link. Password, token and similar values in
48
+ page URLs are replaced before storage.
49
+ - **Crawlers are not recorded.** Bots that run JavaScript are refused by the
50
+ tracker and again by the collector.
51
+ - **Erase on request.** `ossClarity("visitorId")` gives a visitor their id;
52
+ `manage.py oss_clarity_erase_visitor <id>` deletes everything held about them.
53
+ `ossClarity("forget")` clears the ids in their browser.
54
+ - **Retention.** Hits and recordings are deleted after 30 days by default.
55
+
56
+ ## Install
57
+
58
+ ```sh
59
+ pip install "oss-clarity[django]"
60
+ ```
61
+
62
+ Python 3.11 to 3.14, Django 5.2, 6.0 and 6.1, SQLite or PostgreSQL.
63
+
64
+ ## Set up
65
+
66
+ **1. Settings**
67
+
68
+ ```python
69
+ INSTALLED_APPS = [..., "oss_clarity"]
70
+
71
+ MIDDLEWARE = [
72
+ "oss_clarity.middleware.PublicEndpointsMiddleware", # first
73
+ ...,
74
+ ]
75
+ ```
76
+
77
+ The middleware is only needed if something else in your stack (django-cors-headers,
78
+ a no-store cache policy) would override the public endpoints' headers. It is safe
79
+ to always include. Every other setting has a default; see
80
+ [settings](https://github.com/meharaj-007/oss-clarity/blob/v0.1.2/docs/settings.md).
81
+
82
+ **2. URLs**
83
+
84
+ ```python
85
+ urlpatterns = [
86
+ ...,
87
+ path("oc/", include("oss_clarity.urls.public")), # tracker and collector
88
+ path("oc-api/", include("oss_clarity.urls.api")), # read-only API, optional
89
+ ]
90
+ ```
91
+
92
+ Then `python manage.py migrate`.
93
+
94
+ **3. Jobs**, every five minutes from cron (or use the
95
+ [Celery tasks](https://github.com/meharaj-007/oss-clarity/blob/v0.1.2/docs/jobs.md)):
96
+
97
+ ```cron
98
+ */5 * * * * cd /srv/app && python manage.py oss_clarity_run_jobs
99
+ ```
100
+
101
+ **4. The snippet.** Add a site in the admin (Session replay and heatmaps → Sites),
102
+ switch recording on in its recording settings if you want replays, and paste the
103
+ snippet it shows into your pages' `<head>`:
104
+
105
+ ```html
106
+ <script async src="https://your-app.example.com/oc/t/<site key>.js"></script>
107
+ ```
108
+
109
+ Visits appear as hits straight away. Recordings are analysed a few minutes after a
110
+ visit ends, and heatmaps update hourly.
111
+
112
+ To see it all working on your own machine first, run the
113
+ [example project](https://github.com/meharaj-007/oss-clarity/blob/v0.1.2/example/README.md).
114
+
115
+ ## Documentation
116
+
117
+ - [Signals](https://github.com/meharaj-007/oss-clarity/blob/v0.1.2/docs/signals.md): what each one means
118
+ - [Thresholds](https://github.com/meharaj-007/oss-clarity/blob/v0.1.2/docs/thresholds.md): the numbers, and how to measure them
119
+ - [Settings](https://github.com/meharaj-007/oss-clarity/blob/v0.1.2/docs/settings.md): every key
120
+ - [Storage](https://github.com/meharaj-007/oss-clarity/blob/v0.1.2/docs/storage.md): local disk or S3
121
+ - [Jobs](https://github.com/meharaj-007/oss-clarity/blob/v0.1.2/docs/jobs.md): cron or Celery
122
+ - [JSON API](https://github.com/meharaj-007/oss-clarity/blob/v0.1.2/docs/api.md)
123
+ - [Upgrading](https://github.com/meharaj-007/oss-clarity/blob/v0.1.2/docs/upgrading.md)
124
+
125
+ ## Limits
126
+
127
+ - One recording per visit, at most 10 MiB, 128 pages and 120 minutes by default.
128
+ - Replays load images, fonts and styles from your live site, so ones changed or
129
+ removed since render differently.
130
+ - Heatmaps group pages by path (query strings ignored, trailing slashes folded)
131
+ and by device class. Clicks are placed on the element when the snapshot still
132
+ has it, and by position otherwise.
133
+ - Automated browsers (`navigator.webdriver`, headless Chrome) are treated as
134
+ crawlers and never recorded.
135
+ - No multi-tenant accounts, billing or quotas: that is your project's business.
136
+
137
+ ## Development
138
+
139
+ ```sh
140
+ pip install -e ".[django,dev]"
141
+ pytest
142
+ ruff check . && ruff format --check .
143
+ cd js && npm ci && npm run typecheck && npm run build # rebuilds the committed bundles
144
+ ```
145
+
146
+ ## Licence
147
+
148
+ MIT. See [LICENSE](https://github.com/meharaj-007/oss-clarity/blob/v0.1.2/LICENSE).
149
+ The bundled rrweb and its dependencies are listed in
150
+ [THIRD_PARTY_NOTICES.md](https://github.com/meharaj-007/oss-clarity/blob/v0.1.2/THIRD_PARTY_NOTICES.md).