# Django Clickify
[](https://badge.fury.io/py/django-clickify)
[](https://opensource.org/licenses/MIT)
A simple Django app to track clicks on any link (e.g., affiliate links, outbound links, file downloads) with rate limiting, IP filtering, and geolocation.
## Features
* **Click Tracking**: Logs every click on a tracked link, including IP address, user agent, and timestamp.
* **Geolocation**: Automatically enriches click logs with the country and city of the request's IP address via a web API.
* **Rate Limiting**: Prevents abuse by limiting the number of clicks per IP address in a given timeframe.
* **IP Filtering**: Easily configure allowlists and blocklists for IP addresses.
* **Secure**: Protects against path traversal attacks.
* **Django Admin Integration**: Create and manage your tracked links directly in the Django admin.
* **Template Tag & DRF View**: Provides both a simple template tag for traditional Django templates and a DRF API view for headless/JavaScript applications.
## Installation
1. Install the package from PyPI:
```bash
pip install django-clickify
```
2. Add `'clickify'` to your `INSTALLED_APPS` in `settings.py`:
```python
INSTALLED_APPS = [
# ...
'clickify',
]
```
3. Run migrations to create the necessary database models:
```bash
python manage.py migrate
```
4. **For API support (Optional)**: If you plan to use the DRF view, you must also install `djangorestframework` and add it to your `INSTALLED_APPS`.
```bash
pip install django-clickify[drf]
```
```python
INSTALLED_APPS = [
# ...
'rest_framework',
'clickify',
]
```
## Configuration
### 1. Middleware (for IP Filtering)
To enable the IP allowlist and blocklist feature, add the `IPFilterMiddleware` to your `settings.py`.
```python
MIDDLEWARE = [
# ...
'clickify.middleware.IPFilterMiddleware',
# ...
]
```
### 2. Settings (Optional)
You can customize the behavior of `django-clickify` by adding the following settings to your `settings.py`:
* `CLICKIFY_GEOLOCATION`: A boolean to enable or disable geolocation. Defaults to `True`.
* `CLICKIFY_RATE_LIMIT`: The rate limit for clicks. Defaults to `'5/m'`.
* `CLICKIFY_IP_ALLOWLIST`: A list of IP addresses that are always allowed. Defaults to `[]`.
* `CLICKIFY_IP_BLOCKLIST`: A list of IP addresses that are always blocked. Defaults to `[]`.
## Testing
To run the tests for this project, you'll need to have `pytest` and `pytest-django` installed. You can install them with:
```bash
pip install pytest pytest-django
```
Then, you can run the tests from the root of the project with:
```bash
poetry run pytest
```
This will run all the tests in the `tests/` directory.
## Usage
### Option 1: Template-Based Usage
This is the standard way to use the app in traditional Django projects.
#### Step 1: Create a Tracked Link
In your Django Admin, go to the "Clickify" section and create a new "Tracked Link". This target can be any URL you want to track clicks on.
The `Target Url` can point to any type of file (e.g., PDF, ZIP, MP3, MP4, TXT) or any webpage. The link can be hosted anywhere, such as Amazon S3, a personal blog, or an affiliate partner's site.
* **Name:** `Monthly Report PDF`
* **Slug:** `monthly-report-pdf` (this will be auto-populated from the name)
* **Target Url:** `https://your-s3-bucket.s3.amazonaws.com/reports/monthly-summary.pdf`
#### Step 2: Include Clickify URLs
In your project's `urls.py`, include the `clickify` URL patterns.
```python
# your_project/urls.py
from django.urls import path, include
urlpatterns = [
# ... your other urls
path('track/', include('clickify.urls', namespace='clickify')),
]
```
#### Step 3: Create the Tracked Link
In your Django template, use the `track_url` template tag to generate the tracking link. Use the slug of the `TrackedLink` you created in Step 1.
```html
<!-- your_app/templates/my_template.html -->
{% load clickify_tags %}
<a href="{% track_url 'monthly-report-pdf' %}">
Get Monthly Summary
</a>
```
### Option 2: API Usage (for Headless/JS Frameworks)
If you are using a JavaScript frontend (like React, Vue, etc.) or need a programmatic way to get a tracked URL, you can use the DRF API endpoint.
#### Step 1: Create a Tracked Link
Follow Step 1 from the template-based usage above.
#### Step 2: Include Clickify DRF URLs
In your project's `urls.py`, include the `clickify.drf_urls` patterns.
```python
# your_project/urls.py
from django.urls import path, include
urlpatterns = [
# ... your other urls
path('api/track/', include('clickify.drf_urls', namespace='clickify-api')),
]
```
#### Step 3: Make the API Request
From your frontend, make a `POST` request to the API endpoint using the slug of your `TrackedLink`.
**Endpoint**: `POST /api/track/<slug>/`
A successful request will track the click and return the actual file URL, which you can then use to trigger the click or redirection on the client-side.
**Example using JavaScript `fetch`:**
```javascript
fetch('/api/track/monthly-report-pdf/', {
method: 'POST',
headers: {
// Include CSRF token if necessary for your setup
'X-CSRFToken': 'YourCsrfTokenHere'
}
})
.then(response => response.json())
.then(data => {
if (data.target_url) {
console.log("Click tracked. Redirecting to:", data.target_url);
// Redirect the user to the URL
window.location.href = data.target_url;
} else {
console.error("Failed to track click:", data);
}
})
.catch(error => {
console.error('Error:', error);
});
```
**Successful Response (`200 OK`):**
```json
{
"message": "Click tracked successfully",
"target_url": "https://your-s3-bucket.s3.amazonaws.com/reports/monthly-summary.pdf"
}
```
**Failure Responses**
If the request fails, you might receive one of the following error responses:
* **404 Not Found:**
```json
{
"detail": "Not found."
}
```
* **429 Too Many Requests:**
```json
{
"error": "Rate limit exceeded. Please try again later"
}
```
* **403 Forbidden:** (If IP filtering is enabled and the IP is blocked)
This will typically return a plain text response like:
```
IP address blocked.
```
### How It Works
1. A user clicks a tracked link (`/track/monthly-report-pdf/`) or a `POST` request is sent to the API.
2. The view or API view records the click event in the database, associating it with the correct `TrackedLink`.
3. The standard view issues a `302 Redirect` to the `target_url`. The API view returns a JSON response containing the `target_url`.
4. The user's browser is redirected to the final destination.
This approach is powerful because if you ever need to change the link's destination, you only need to update the `Target Url` in the Django Admin. All your tracked links and API calls will continue to work correctly.
## Contributing
Contributions are welcome! If you'd like to contribute to this project, please follow these steps:
1. Fork the repository.
2. Create a new branch for your feature or bug fix.
3. Make your changes and add tests for them.
4. Ensure the tests pass by running `poetry run pytest`.
5. Create a pull request with a clear description of your changes.
Raw data
{
"_id": null,
"home_page": "https://github.com/romjanxr/django-clickify",
"name": "django-clickify",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.10",
"maintainer_email": null,
"keywords": "django, click, tracker, ratelimit, ipfilter, geolocation",
"author": "Romjan Ali",
"author_email": "romjanvr5@gmail.com",
"download_url": "https://files.pythonhosted.org/packages/b1/05/14186c23b1f4b04a34d9eae28405505c07858ab07f513259b63c7d2d3e2a/django_clickify-0.1.1.tar.gz",
"platform": null,
"description": "# Django Clickify\n\n[](https://badge.fury.io/py/django-clickify)\n[](https://opensource.org/licenses/MIT)\n\nA simple Django app to track clicks on any link (e.g., affiliate links, outbound links, file downloads) with rate limiting, IP filtering, and geolocation.\n\n## Features\n\n* **Click Tracking**: Logs every click on a tracked link, including IP address, user agent, and timestamp.\n* **Geolocation**: Automatically enriches click logs with the country and city of the request's IP address via a web API.\n* **Rate Limiting**: Prevents abuse by limiting the number of clicks per IP address in a given timeframe.\n* **IP Filtering**: Easily configure allowlists and blocklists for IP addresses.\n* **Secure**: Protects against path traversal attacks.\n* **Django Admin Integration**: Create and manage your tracked links directly in the Django admin.\n* **Template Tag & DRF View**: Provides both a simple template tag for traditional Django templates and a DRF API view for headless/JavaScript applications.\n\n## Installation\n\n1. Install the package from PyPI:\n\n ```bash\n pip install django-clickify\n ```\n\n2. Add `'clickify'` to your `INSTALLED_APPS` in `settings.py`:\n\n ```python\n INSTALLED_APPS = [\n # ...\n 'clickify',\n ]\n ```\n\n3. Run migrations to create the necessary database models:\n\n ```bash\n python manage.py migrate\n ```\n\n4. **For API support (Optional)**: If you plan to use the DRF view, you must also install `djangorestframework` and add it to your `INSTALLED_APPS`.\n\n ```bash\n pip install django-clickify[drf]\n ```\n ```python\n INSTALLED_APPS = [\n # ...\n 'rest_framework',\n 'clickify',\n ]\n ```\n\n## Configuration\n\n### 1. Middleware (for IP Filtering)\n\nTo enable the IP allowlist and blocklist feature, add the `IPFilterMiddleware` to your `settings.py`.\n\n```python\nMIDDLEWARE = [\n # ...\n 'clickify.middleware.IPFilterMiddleware',\n # ...\n]\n```\n\n### 2. Settings (Optional)\n\nYou can customize the behavior of `django-clickify` by adding the following settings to your `settings.py`:\n\n* `CLICKIFY_GEOLOCATION`: A boolean to enable or disable geolocation. Defaults to `True`.\n* `CLICKIFY_RATE_LIMIT`: The rate limit for clicks. Defaults to `'5/m'`.\n* `CLICKIFY_IP_ALLOWLIST`: A list of IP addresses that are always allowed. Defaults to `[]`.\n* `CLICKIFY_IP_BLOCKLIST`: A list of IP addresses that are always blocked. Defaults to `[]`.\n\n## Testing\n\nTo run the tests for this project, you'll need to have `pytest` and `pytest-django` installed. You can install them with:\n\n```bash\npip install pytest pytest-django\n```\n\nThen, you can run the tests from the root of the project with:\n\n```bash\npoetry run pytest\n```\n\nThis will run all the tests in the `tests/` directory.\n\n## Usage\n\n### Option 1: Template-Based Usage\n\nThis is the standard way to use the app in traditional Django projects.\n\n#### Step 1: Create a Tracked Link\n\nIn your Django Admin, go to the \"Clickify\" section and create a new \"Tracked Link\". This target can be any URL you want to track clicks on.\n\nThe `Target Url` can point to any type of file (e.g., PDF, ZIP, MP3, MP4, TXT) or any webpage. The link can be hosted anywhere, such as Amazon S3, a personal blog, or an affiliate partner's site.\n\n* **Name:** `Monthly Report PDF`\n* **Slug:** `monthly-report-pdf` (this will be auto-populated from the name)\n* **Target Url:** `https://your-s3-bucket.s3.amazonaws.com/reports/monthly-summary.pdf`\n\n#### Step 2: Include Clickify URLs\n\nIn your project's `urls.py`, include the `clickify` URL patterns.\n\n```python\n# your_project/urls.py\nfrom django.urls import path, include\n\nurlpatterns = [\n # ... your other urls\n path('track/', include('clickify.urls', namespace='clickify')),\n]\n```\n\n#### Step 3: Create the Tracked Link\n\nIn your Django template, use the `track_url` template tag to generate the tracking link. Use the slug of the `TrackedLink` you created in Step 1.\n\n```html\n<!-- your_app/templates/my_template.html -->\n{% load clickify_tags %}\n\n<a href=\"{% track_url 'monthly-report-pdf' %}\">\n Get Monthly Summary\n</a>\n```\n\n### Option 2: API Usage (for Headless/JS Frameworks)\n\nIf you are using a JavaScript frontend (like React, Vue, etc.) or need a programmatic way to get a tracked URL, you can use the DRF API endpoint.\n\n#### Step 1: Create a Tracked Link\n\nFollow Step 1 from the template-based usage above.\n\n#### Step 2: Include Clickify DRF URLs\n\nIn your project's `urls.py`, include the `clickify.drf_urls` patterns.\n\n```python\n# your_project/urls.py\nfrom django.urls import path, include\n\nurlpatterns = [\n # ... your other urls\n path('api/track/', include('clickify.drf_urls', namespace='clickify-api')),\n]\n```\n\n#### Step 3: Make the API Request\n\nFrom your frontend, make a `POST` request to the API endpoint using the slug of your `TrackedLink`.\n\n**Endpoint**: `POST /api/track/<slug>/`\n\nA successful request will track the click and return the actual file URL, which you can then use to trigger the click or redirection on the client-side.\n\n**Example using JavaScript `fetch`:**\n\n```javascript\nfetch('/api/track/monthly-report-pdf/', {\n method: 'POST',\n headers: {\n // Include CSRF token if necessary for your setup\n 'X-CSRFToken': 'YourCsrfTokenHere' \n }\n})\n.then(response => response.json())\n.then(data => {\n if (data.target_url) {\n console.log(\"Click tracked. Redirecting to:\", data.target_url);\n // Redirect the user to the URL\n window.location.href = data.target_url;\n } else {\n console.error(\"Failed to track click:\", data);\n }\n})\n.catch(error => {\n console.error('Error:', error);\n});\n```\n\n**Successful Response (`200 OK`):**\n```json\n{\n \"message\": \"Click tracked successfully\",\n \"target_url\": \"https://your-s3-bucket.s3.amazonaws.com/reports/monthly-summary.pdf\"\n}\n```\n\n**Failure Responses**\n\nIf the request fails, you might receive one of the following error responses:\n\n* **404 Not Found:**\n\n ```json\n {\n \"detail\": \"Not found.\"\n }\n ```\n\n* **429 Too Many Requests:**\n\n ```json\n {\n \"error\": \"Rate limit exceeded. Please try again later\"\n }\n ```\n\n* **403 Forbidden:** (If IP filtering is enabled and the IP is blocked)\n\n This will typically return a plain text response like:\n ```\n IP address blocked.\n ```\n\n### How It Works\n\n1. A user clicks a tracked link (`/track/monthly-report-pdf/`) or a `POST` request is sent to the API.\n2. The view or API view records the click event in the database, associating it with the correct `TrackedLink`.\n3. The standard view issues a `302 Redirect` to the `target_url`. The API view returns a JSON response containing the `target_url`.\n4. The user's browser is redirected to the final destination.\n\nThis approach is powerful because if you ever need to change the link's destination, you only need to update the `Target Url` in the Django Admin. All your tracked links and API calls will continue to work correctly.\n\n## Contributing\n\nContributions are welcome! If you'd like to contribute to this project, please follow these steps:\n\n1. Fork the repository.\n2. Create a new branch for your feature or bug fix.\n3. Make your changes and add tests for them.\n4. Ensure the tests pass by running `poetry run pytest`.\n5. Create a pull request with a clear description of your changes.",
"bugtrack_url": null,
"license": "MIT",
"summary": "A Django app to track link clicks with rate limiting, IP filtering, and geolocation.",
"version": "0.1.1",
"project_urls": {
"Homepage": "https://github.com/romjanxr/django-clickify",
"Repository": "https://github.com/romjanxr/django-clickify"
},
"split_keywords": [
"django",
" click",
" tracker",
" ratelimit",
" ipfilter",
" geolocation"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "c8d09ce0bfb318b617f9d0bdaa216a62a0b475bb995088aa5e7c3bfae92a46c3",
"md5": "c9857fe916ec6ee43175393384217c91",
"sha256": "891dc2616bb3f9cc8049e44f70cb6ef5676fe66ec48d1028d5f14f0afed09acf"
},
"downloads": -1,
"filename": "django_clickify-0.1.1-py3-none-any.whl",
"has_sig": false,
"md5_digest": "c9857fe916ec6ee43175393384217c91",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.10",
"size": 11813,
"upload_time": "2025-08-28T10:48:20",
"upload_time_iso_8601": "2025-08-28T10:48:20.594248Z",
"url": "https://files.pythonhosted.org/packages/c8/d0/9ce0bfb318b617f9d0bdaa216a62a0b475bb995088aa5e7c3bfae92a46c3/django_clickify-0.1.1-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "b10514186c23b1f4b04a34d9eae28405505c07858ab07f513259b63c7d2d3e2a",
"md5": "d041490d5a3a3a6e081b6ca083a00cf5",
"sha256": "5c9d87d80a6a7258dab5d6bf507a2b31f59efe2dfc8a5203c3bf2d604f7afae1"
},
"downloads": -1,
"filename": "django_clickify-0.1.1.tar.gz",
"has_sig": false,
"md5_digest": "d041490d5a3a3a6e081b6ca083a00cf5",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.10",
"size": 10573,
"upload_time": "2025-08-28T10:48:22",
"upload_time_iso_8601": "2025-08-28T10:48:22.185078Z",
"url": "https://files.pythonhosted.org/packages/b1/05/14186c23b1f4b04a34d9eae28405505c07858ab07f513259b63c7d2d3e2a/django_clickify-0.1.1.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-08-28 10:48:22",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "romjanxr",
"github_project": "django-clickify",
"travis_ci": false,
"coveralls": false,
"github_actions": false,
"lcname": "django-clickify"
}