djangocms-ab-testing 0.1.0__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 (25) hide show
  1. djangocms_ab_testing-0.1.0/LICENSE +21 -0
  2. djangocms_ab_testing-0.1.0/PKG-INFO +205 -0
  3. djangocms_ab_testing-0.1.0/README.md +174 -0
  4. djangocms_ab_testing-0.1.0/djangocms_ab_testing/__init__.py +0 -0
  5. djangocms_ab_testing-0.1.0/djangocms_ab_testing/ab_utils.py +42 -0
  6. djangocms_ab_testing-0.1.0/djangocms_ab_testing/admin.py +287 -0
  7. djangocms_ab_testing-0.1.0/djangocms_ab_testing/apps.py +7 -0
  8. djangocms_ab_testing-0.1.0/djangocms_ab_testing/cms_plugins.py +64 -0
  9. djangocms_ab_testing-0.1.0/djangocms_ab_testing/conf.py +7 -0
  10. djangocms_ab_testing-0.1.0/djangocms_ab_testing/management/__init__.py +0 -0
  11. djangocms_ab_testing-0.1.0/djangocms_ab_testing/management/commands/__init__.py +0 -0
  12. djangocms_ab_testing-0.1.0/djangocms_ab_testing/management/commands/seed_ab_data.py +77 -0
  13. djangocms_ab_testing-0.1.0/djangocms_ab_testing/middleware.py +25 -0
  14. djangocms_ab_testing-0.1.0/djangocms_ab_testing/migrations/0001_initial.py +88 -0
  15. djangocms_ab_testing-0.1.0/djangocms_ab_testing/migrations/__init__.py +0 -0
  16. djangocms_ab_testing-0.1.0/djangocms_ab_testing/models.py +110 -0
  17. djangocms_ab_testing-0.1.0/djangocms_ab_testing/urls.py +7 -0
  18. djangocms_ab_testing-0.1.0/djangocms_ab_testing/views.py +51 -0
  19. djangocms_ab_testing-0.1.0/djangocms_ab_testing.egg-info/PKG-INFO +205 -0
  20. djangocms_ab_testing-0.1.0/djangocms_ab_testing.egg-info/SOURCES.txt +23 -0
  21. djangocms_ab_testing-0.1.0/djangocms_ab_testing.egg-info/dependency_links.txt +1 -0
  22. djangocms_ab_testing-0.1.0/djangocms_ab_testing.egg-info/requires.txt +4 -0
  23. djangocms_ab_testing-0.1.0/djangocms_ab_testing.egg-info/top_level.txt +1 -0
  24. djangocms_ab_testing-0.1.0/pyproject.toml +52 -0
  25. djangocms_ab_testing-0.1.0/setup.cfg +4 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Sergei Gordeichuk
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,205 @@
1
+ Metadata-Version: 2.4
2
+ Name: djangocms-ab-testing
3
+ Version: 0.1.0
4
+ Summary: A/B testing plugin for django CMS with round-robin assignment, cookie-based persistence, event tracking, and an admin dashboard.
5
+ Author: Sergei Gordeichuk
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/sgordeychuk/djangocms-ab-testing
8
+ Project-URL: Documentation, https://github.com/sgordeychuk/djangocms-ab-testing#readme
9
+ Project-URL: Repository, https://github.com/sgordeychuk/djangocms-ab-testing
10
+ Project-URL: Issues, https://github.com/sgordeychuk/djangocms-ab-testing/issues
11
+ Keywords: django-cms,ab-testing,split-testing,conversion-optimization,cms-plugin,django,a-b-testing,multivariate-testing
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Framework :: Django
14
+ Classifier: Framework :: Django :: 4.2
15
+ Classifier: Framework :: Django CMS
16
+ Classifier: Framework :: Django CMS :: 3.11
17
+ Classifier: Intended Audience :: Developers
18
+ Classifier: Programming Language :: Python :: 3
19
+ Classifier: Programming Language :: Python :: 3.9
20
+ Classifier: Programming Language :: Python :: 3.10
21
+ Classifier: Programming Language :: Python :: 3.11
22
+ Classifier: Programming Language :: Python :: 3.12
23
+ Requires-Python: >=3.9
24
+ Description-Content-Type: text/markdown
25
+ License-File: LICENSE
26
+ Requires-Dist: django>=3.2
27
+ Requires-Dist: django-cms>=3.11
28
+ Requires-Dist: django-import-export>=3.0
29
+ Requires-Dist: user-agents>=2.0
30
+ Dynamic: license-file
31
+
32
+ # djangocms-ab-testing
33
+
34
+ [![PyPI version](https://img.shields.io/pypi/v/djangocms-ab-testing.svg)](https://pypi.org/project/djangocms-ab-testing/)
35
+ [![Python versions](https://img.shields.io/pypi/pyversions/djangocms-ab-testing.svg)](https://pypi.org/project/djangocms-ab-testing/)
36
+ [![Django versions](https://img.shields.io/badge/django-3.2%20%7C%204.2-blue.svg)](https://pypi.org/project/djangocms-ab-testing/)
37
+ [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](https://opensource.org/licenses/MIT)
38
+
39
+ A full-featured **A/B testing** (split testing) plugin for **django CMS**. Run conversion optimization experiments directly in the CMS page editor with round-robin variant assignment, cookie-based persistence, client-side event tracking, and a built-in admin dashboard with Chart.js visualizations.
40
+
41
+ ## Features
42
+
43
+ - **CMS plugin-based setup** - Add A/B test containers and variants directly in the django CMS page editor
44
+ - **Round-robin assignment** - Fair variant distribution using an atomic database counter
45
+ - **Cookie persistence** - Visitors see the same variant for 30 days (`ab_variant_<slug>`)
46
+ - **Event tracking API** - POST events to `/api/ab-event/` with CSRF protection
47
+ - **Auto "view" tracking** - Fires automatically when a variant is rendered
48
+ - **Bootstrap modal tracking** - Tracks `shown.bs.modal`, `hidden.bs.modal`, and CTA button clicks
49
+ - **Configurable actions** - Define custom tracking events via `AB_TESTING_VALID_ACTIONS` setting
50
+ - **Admin dashboard** - Chart.js-powered visualizations with summary cards, per-variant stats, daily trends, and conversion rate charts
51
+ - **Distribution breakdowns** - Analyze results by device type, browser, OS, and screen size
52
+ - **Filtering** - Filter dashboard data by date range and device properties
53
+ - **CSV export** - Export event data via django-import-export
54
+ - **Cache control** - Pages with A/B tests automatically get `Cache-Control: private, no-store`
55
+
56
+ ## Screenshots
57
+
58
+ ### Light theme
59
+ ![Dashboard - Light theme](docs/ab_test_screenshot_light.png)
60
+
61
+ ### Dark theme
62
+ ![Dashboard - Dark theme](docs/ab_test_screenshot_dark.png)
63
+
64
+ ## Installation
65
+
66
+ ```sh
67
+ pip install djangocms-ab-testing
68
+ ```
69
+
70
+ Add to `INSTALLED_APPS`:
71
+
72
+ ```python
73
+ INSTALLED_APPS = [
74
+ # ...
75
+ "djangocms_ab_testing",
76
+ ]
77
+ ```
78
+
79
+ Add the middleware (after `SessionMiddleware`):
80
+
81
+ ```python
82
+ MIDDLEWARE = [
83
+ # ...
84
+ "django.contrib.sessions.middleware.SessionMiddleware",
85
+ "djangocms_ab_testing.middleware.ABCookieMiddleware",
86
+ # ...
87
+ ]
88
+ ```
89
+
90
+ Add the URL config:
91
+
92
+ ```python
93
+ from django.urls import include, path
94
+
95
+ urlpatterns = [
96
+ # ...
97
+ path("api/", include("djangocms_ab_testing.urls")),
98
+ ]
99
+ ```
100
+
101
+ Run migrations:
102
+
103
+ ```sh
104
+ python manage.py migrate djangocms_ab_testing
105
+ ```
106
+
107
+ ## Usage
108
+
109
+ ### 1. Create an AB Test
110
+
111
+ Go to **Django Admin > AB Tests** and create a test with a name and slug.
112
+
113
+ ### 2. Add CMS Plugins
114
+
115
+ In the django CMS page editor:
116
+
117
+ 1. Add an **A/B Test Container** plugin and link it to your test
118
+ 2. Inside the container, add **A/B Test Variant** plugins (e.g. variant key `A`, `B`)
119
+ 3. Add your content inside each variant
120
+
121
+ ### 3. Track Events
122
+
123
+ Include the tracking script in your template:
124
+
125
+ ```html
126
+ <script src="{% static 'djangocms_ab_testing/js/ab_tracking.js' %}"></script>
127
+ ```
128
+
129
+ The script auto-initializes, fires a `view` event when the variant is rendered, and tracks Bootstrap modal events (`shown.bs.modal`, `hidden.bs.modal`). Add the `ab-request-btn` class to CTA buttons inside modals to track conversion clicks.
130
+
131
+ For custom tracking, call `window.initABTracking()` after dynamic content loads.
132
+
133
+ ### 4. View Results
134
+
135
+ Open any AB Test in the admin to see the dashboard with:
136
+
137
+ - Summary cards (total events, unique sessions, counter)
138
+ - Per-variant stats table (views, opens, requests, closes, conversion rate)
139
+ - Daily trends and conversion rate charts
140
+ - Distribution breakdowns by device, browser, OS, screen size
141
+ - Filterable by date range and device properties
142
+ - CSV export via django-import-export
143
+
144
+ ## Configuration
145
+
146
+ ### Custom Tracking Actions
147
+
148
+ By default, the following actions are tracked: `view`, `opened`, `closed`, `requested`.
149
+
150
+ To define custom actions, add `AB_TESTING_VALID_ACTIONS` to your Django settings:
151
+
152
+ ```python
153
+ AB_TESTING_VALID_ACTIONS = {"view", "opened", "closed", "requested", "submitted", "purchased"}
154
+ ```
155
+
156
+ The event tracking API will only accept actions in this set. The admin dashboard and seed command will also use these actions automatically.
157
+
158
+ ## How It Works
159
+
160
+ - **Variant assignment**: Round-robin via atomic database counter
161
+ - **Persistence**: 30-day cookie per test (`ab_variant_<slug>`)
162
+ - **Cache**: Pages with A/B tests get `Cache-Control: private, no-store`
163
+ - **Events**: Tracked via POST to `/api/ab-event/` with CSRF protection
164
+
165
+ ## Management Commands
166
+
167
+ ```sh
168
+ python manage.py seed_ab_data --events 500 --days 30
169
+ ```
170
+
171
+ Generates dummy event data for dashboard testing.
172
+
173
+ ## Publishing to PyPI
174
+
175
+ 1. Install build tools:
176
+
177
+ ```sh
178
+ pip install build twine
179
+ ```
180
+
181
+ 2. Build the package:
182
+
183
+ ```sh
184
+ python -m build
185
+ ```
186
+
187
+ 3. Upload to TestPyPI first:
188
+
189
+ ```sh
190
+ twine upload --repository testpypi dist/*
191
+ ```
192
+
193
+ 4. Upload to PyPI:
194
+
195
+ ```sh
196
+ twine upload dist/*
197
+ ```
198
+
199
+ ## Contributing
200
+
201
+ Contributions are welcome! Please open an issue or submit a pull request on [GitHub](https://github.com/sgordeychuk/djangocms-ab-testing).
202
+
203
+ ## License
204
+
205
+ MIT
@@ -0,0 +1,174 @@
1
+ # djangocms-ab-testing
2
+
3
+ [![PyPI version](https://img.shields.io/pypi/v/djangocms-ab-testing.svg)](https://pypi.org/project/djangocms-ab-testing/)
4
+ [![Python versions](https://img.shields.io/pypi/pyversions/djangocms-ab-testing.svg)](https://pypi.org/project/djangocms-ab-testing/)
5
+ [![Django versions](https://img.shields.io/badge/django-3.2%20%7C%204.2-blue.svg)](https://pypi.org/project/djangocms-ab-testing/)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](https://opensource.org/licenses/MIT)
7
+
8
+ A full-featured **A/B testing** (split testing) plugin for **django CMS**. Run conversion optimization experiments directly in the CMS page editor with round-robin variant assignment, cookie-based persistence, client-side event tracking, and a built-in admin dashboard with Chart.js visualizations.
9
+
10
+ ## Features
11
+
12
+ - **CMS plugin-based setup** - Add A/B test containers and variants directly in the django CMS page editor
13
+ - **Round-robin assignment** - Fair variant distribution using an atomic database counter
14
+ - **Cookie persistence** - Visitors see the same variant for 30 days (`ab_variant_<slug>`)
15
+ - **Event tracking API** - POST events to `/api/ab-event/` with CSRF protection
16
+ - **Auto "view" tracking** - Fires automatically when a variant is rendered
17
+ - **Bootstrap modal tracking** - Tracks `shown.bs.modal`, `hidden.bs.modal`, and CTA button clicks
18
+ - **Configurable actions** - Define custom tracking events via `AB_TESTING_VALID_ACTIONS` setting
19
+ - **Admin dashboard** - Chart.js-powered visualizations with summary cards, per-variant stats, daily trends, and conversion rate charts
20
+ - **Distribution breakdowns** - Analyze results by device type, browser, OS, and screen size
21
+ - **Filtering** - Filter dashboard data by date range and device properties
22
+ - **CSV export** - Export event data via django-import-export
23
+ - **Cache control** - Pages with A/B tests automatically get `Cache-Control: private, no-store`
24
+
25
+ ## Screenshots
26
+
27
+ ### Light theme
28
+ ![Dashboard - Light theme](docs/ab_test_screenshot_light.png)
29
+
30
+ ### Dark theme
31
+ ![Dashboard - Dark theme](docs/ab_test_screenshot_dark.png)
32
+
33
+ ## Installation
34
+
35
+ ```sh
36
+ pip install djangocms-ab-testing
37
+ ```
38
+
39
+ Add to `INSTALLED_APPS`:
40
+
41
+ ```python
42
+ INSTALLED_APPS = [
43
+ # ...
44
+ "djangocms_ab_testing",
45
+ ]
46
+ ```
47
+
48
+ Add the middleware (after `SessionMiddleware`):
49
+
50
+ ```python
51
+ MIDDLEWARE = [
52
+ # ...
53
+ "django.contrib.sessions.middleware.SessionMiddleware",
54
+ "djangocms_ab_testing.middleware.ABCookieMiddleware",
55
+ # ...
56
+ ]
57
+ ```
58
+
59
+ Add the URL config:
60
+
61
+ ```python
62
+ from django.urls import include, path
63
+
64
+ urlpatterns = [
65
+ # ...
66
+ path("api/", include("djangocms_ab_testing.urls")),
67
+ ]
68
+ ```
69
+
70
+ Run migrations:
71
+
72
+ ```sh
73
+ python manage.py migrate djangocms_ab_testing
74
+ ```
75
+
76
+ ## Usage
77
+
78
+ ### 1. Create an AB Test
79
+
80
+ Go to **Django Admin > AB Tests** and create a test with a name and slug.
81
+
82
+ ### 2. Add CMS Plugins
83
+
84
+ In the django CMS page editor:
85
+
86
+ 1. Add an **A/B Test Container** plugin and link it to your test
87
+ 2. Inside the container, add **A/B Test Variant** plugins (e.g. variant key `A`, `B`)
88
+ 3. Add your content inside each variant
89
+
90
+ ### 3. Track Events
91
+
92
+ Include the tracking script in your template:
93
+
94
+ ```html
95
+ <script src="{% static 'djangocms_ab_testing/js/ab_tracking.js' %}"></script>
96
+ ```
97
+
98
+ The script auto-initializes, fires a `view` event when the variant is rendered, and tracks Bootstrap modal events (`shown.bs.modal`, `hidden.bs.modal`). Add the `ab-request-btn` class to CTA buttons inside modals to track conversion clicks.
99
+
100
+ For custom tracking, call `window.initABTracking()` after dynamic content loads.
101
+
102
+ ### 4. View Results
103
+
104
+ Open any AB Test in the admin to see the dashboard with:
105
+
106
+ - Summary cards (total events, unique sessions, counter)
107
+ - Per-variant stats table (views, opens, requests, closes, conversion rate)
108
+ - Daily trends and conversion rate charts
109
+ - Distribution breakdowns by device, browser, OS, screen size
110
+ - Filterable by date range and device properties
111
+ - CSV export via django-import-export
112
+
113
+ ## Configuration
114
+
115
+ ### Custom Tracking Actions
116
+
117
+ By default, the following actions are tracked: `view`, `opened`, `closed`, `requested`.
118
+
119
+ To define custom actions, add `AB_TESTING_VALID_ACTIONS` to your Django settings:
120
+
121
+ ```python
122
+ AB_TESTING_VALID_ACTIONS = {"view", "opened", "closed", "requested", "submitted", "purchased"}
123
+ ```
124
+
125
+ The event tracking API will only accept actions in this set. The admin dashboard and seed command will also use these actions automatically.
126
+
127
+ ## How It Works
128
+
129
+ - **Variant assignment**: Round-robin via atomic database counter
130
+ - **Persistence**: 30-day cookie per test (`ab_variant_<slug>`)
131
+ - **Cache**: Pages with A/B tests get `Cache-Control: private, no-store`
132
+ - **Events**: Tracked via POST to `/api/ab-event/` with CSRF protection
133
+
134
+ ## Management Commands
135
+
136
+ ```sh
137
+ python manage.py seed_ab_data --events 500 --days 30
138
+ ```
139
+
140
+ Generates dummy event data for dashboard testing.
141
+
142
+ ## Publishing to PyPI
143
+
144
+ 1. Install build tools:
145
+
146
+ ```sh
147
+ pip install build twine
148
+ ```
149
+
150
+ 2. Build the package:
151
+
152
+ ```sh
153
+ python -m build
154
+ ```
155
+
156
+ 3. Upload to TestPyPI first:
157
+
158
+ ```sh
159
+ twine upload --repository testpypi dist/*
160
+ ```
161
+
162
+ 4. Upload to PyPI:
163
+
164
+ ```sh
165
+ twine upload dist/*
166
+ ```
167
+
168
+ ## Contributing
169
+
170
+ Contributions are welcome! Please open an issue or submit a pull request on [GitHub](https://github.com/sgordeychuk/djangocms-ab-testing).
171
+
172
+ ## License
173
+
174
+ MIT
@@ -0,0 +1,42 @@
1
+ from user_agents import parse as ua_parse
2
+
3
+ from djangocms_ab_testing.models import ABCounter
4
+
5
+ COOKIE_NAME_PREFIX = "ab_variant_"
6
+ COOKIE_MAX_AGE = 60 * 60 * 24 * 30 # 30 days
7
+
8
+
9
+ def get_ab_variant(request, test_name, variant_keys):
10
+ """
11
+ Get the variant for this request. Checks cookie first, then round-robin.
12
+ Queues the cookie to be set in the response via middleware.
13
+ """
14
+ cookie_name = COOKIE_NAME_PREFIX + test_name
15
+ variant_key = request.COOKIES.get(cookie_name)
16
+
17
+ if variant_key and variant_key in variant_keys:
18
+ return variant_key
19
+
20
+ # Assign via round-robin
21
+ variant_key = ABCounter.next_variant(test_name, list(variant_keys))
22
+
23
+ # Queue cookie to be set by middleware
24
+ if not hasattr(request, '_ab_cookies_to_set'):
25
+ request._ab_cookies_to_set = {}
26
+ request._ab_cookies_to_set[cookie_name] = variant_key
27
+
28
+ return variant_key
29
+
30
+
31
+ def get_device_info(request):
32
+ """Parse device info from User-Agent header."""
33
+ ua_string = request.META.get('HTTP_USER_AGENT', '')
34
+ ua = ua_parse(ua_string)
35
+ return {
36
+ 'device_type': 'mobile' if ua.is_mobile else ('tablet' if ua.is_tablet else 'desktop'),
37
+ 'browser': str(ua.browser.family),
38
+ 'browser_version': str(ua.browser.version_string),
39
+ 'os': str(ua.os.family),
40
+ 'os_version': str(ua.os.version_string),
41
+ 'is_bot': ua.is_bot,
42
+ }