This repository hosts the source code for the website that manages and serves news for the QGIS welcome page and the QGIS Analytics Dashboard:
Here you'll find everything you need to build, develop, and contribute to these sites.
This repository is only for the QGIS Home Page News Feed (feed.qgis.org) and the QGIS Analytics Dashboard (https://analytics.qgis.org).
If you are looking for the source code or want to contribute to other QGIS websites, please visit their respective repositories below. Each website has its own codebase and contribution process:
- qgis.org (GitHub: QGIS-Website) β QGIS Main Wesite
- hub.qgis.org (GitHub: QGIS-Hub-Website) β QGIS Resources Hub
- plugins.qgis.org (GitHub: QGIS-Plugins-Website) β QGIS Plugins Repository
- planet.qgis.org (GitHub: QGIS-Planet-Website) β QGIS Planet Blog Aggregator
- members.qgis.org (GitHub: QGIS-Members-Website) β QGIS Sustaining Members Portal
- certification.qgis.org (GitHub: QGIS-Certification-Website) β QGIS Certification Programme Platform
- changelog.qgis.org (GitHub: QGIS-Changelog-Website) β QGIS Changelog Manager
- uc2025.qgis.org (GitHub: QGIS-UC-Website) β QGIS User Conference Website
Table of Contents
The QGIS Analytics Dashboard is a web-based interface that provides insights into QGIS usage statistics, including active versions and platform distribution. It is powered by Metabase and is available at https://analytics.qgis.org. The dashboard visualizes aggregated, anonymized data collected from QGIS clients, helping the community and developers understand trends and adoption across regions and platforms.
How Tables Are Aggregated
When a user opens QGIS, their application sends a request to https://feed.qgis.org
. The server processes each request and extracts only three key pieces of information:
- Date (rounded to the nearest day)
- QGIS Version (the version code of the software)
- Country (determined from the IP address, but the IP itself is not stored)
- Operating System (platform string)
This information is then aggregated hourly into three separate tables:
-
Daily Country Table:
- Columns: date, country ISO code, number of hits
- Example:
2024-06-10, DE, 1200
-
Daily QGIS Version Table:
- Columns: date, QGIS version, number of hits
- Example:
2024-06-10, 3.34.0, 800
-
Daily Platform Table:
- Columns: date, OS platform, number of hits
- Example:
2024-06-10, Windows, 900
Each table records the count of requests (hits) for each unique value per day.
How User Data Is Anonymized
-
No IP Addresses Stored: The server uses the IP address only to determine the country. The IP is immediately discarded and never stored.
-
No Persistent Identifiers: No user IDs, device IDs, or other persistent identifiers are collected or stored.
-
Aggregation: Data is stored only as counts per day, per country/version/platform. There is no way to trace data back to an individual user.
-
Rate Limiting:
- Only one hit per IP per hour is counted.
- Only one opening per day is recorded per user (even if they open/close QGIS multiple times).
Summary Table Example
Date | Country | QGIS Version | Platform | Hits |
---|---|---|---|---|
2024-06-10 | DE | 3.34.0 | Windows | 120 |
Privacy Measures
- No personal or device information is stored.
- No sharing with third parties.
- Data is only used in aggregate for analytics.
Gotchas
- Users behind NAT or managed networks may be undercounted.
- Users who disable the news feed are not counted.
- Only one hit per IP per hour/day, so heavy users are not overrepresented.
Home page
A home page that displays feeds as they are rendered in QGIS is now available at the root of the web server /
. Feeds are filterable using the filter widget on the left side. You can directly pass the filter parameters in the url according to the section Available parameters for filters in Endpoint and accepted parameters
Note: When calling the root url from QGIS, the response data is in JSON format. See the section Response data for QGIS in the Endpoint and accepted parameters
Control panel and permissions
Users with staff
flag can enter the control panel at /admin
and add feed entries, by default entries are not published.
Users with superadmin
flag will be notified by email when an entry is added to the feed and will be able to publish the entry.
Appart from superadmin
, only users with the permission qgisfeed | Can publish QGIS feed
can publish the entry. Like the group qgisfeedentry_authors
, the group qgisfeedentry_approver
with the permission qgisfeed | Can publish QGIS feed
are created when a Save
signal from the User
model is detected.
For content field, a hard limit on the number of characters allowed is configurable in administration page (Character limit configurations). If not set, max characters value for this field is 500. If you want to add a custom max characters for this field, the field name value should be content
.
Manage feeds page
Note: The permissions for this page are the same as described in the Control Panel and permissions.
After logging in with the login screen at /accounts/login/
(can be also accessed from the Login button on the Homepage), users are provided with tools to manage feed items:
- A list of feed items, sortable and filterable by title, date published, author, language, need review
- A button to create a new feed item - clicking will take you to a blank feed item form (See Feed item form below)
- Clicking on an item on the list will take you to a feed item form (See Feed item form below)
Feed item form
The feed item form page is displayed when clicking the New entry item button or an item on the list:
- The feed item form is displayed on the left with all the widgets needed to edit the entry. On the right, a preview of the entry as it will be rendered in QGIS. Any edits made in the form shall immediately update the preview.
- In the content widget only the following html tags are allowed: p, strong, italics. A hard limit on the number of characters allowed is configurable in administration page in the model
Character limit configurations
(default is 500). - Once a feed item is created or modified, there will be a review step where the user is asked to confirm that they have checked everything carefully.
- The form is placed in the column Need review in the list before final submission.
- The form must be approved by someone the permission
qgisfeed | Can publish QGIS feed
before it is published.
Endpoint and accepted parameters
The application has a single endpoint available at the web server root /
the reponse is in JSON format.
Example call: http://localhost:8000/
Returned data:
[
{
"pk": 1,
"title": "QGIS acquired by ESRI",
"image": "http://localhost:8000/media/feedimages/image.png",
"content": "<p>QGIS is finally part of the ESRI ecosystem, it has been rebranded as CrashGIS to better integrate with ESRI products line.</p>",
"url": "https://www.qgis.com",
"sticky": true,
"publish_from": 1557419128
},
{
"pk": 2,
"title": "Null Island QGIS Meeting",
"image": "",
"content": "<p>Let's dive in the ocean together!</p>",
"url": null,
"sticky": false,
"publish_from": 1557419128
},
{
"pk": 3,
"title": "QGIS Italian Meeting",
"image": "",
"content": "<p>Ciao from Italy!</p>",
"url": null,
"sticky": false,
"publish_from": 1557419128
}
]
The following parameters can be passed by the client to filter available records.
Parameters are validated and in case they are not valid a Bad Request
HTTP error code 400
is returned.
When after
is passed, only the records that have been published after the given value will be returned.
Accepted values: unix timestamp (UTC)
Example call: http://localhost:8000/?after=1557419013
When lang
is passed, the records that have a different lang
will be excluded from the results. Only the records with null
lang
and the records with a matching lang
will be returned.
Accepted values: ISO-939-1
two letters language code
Example call: http://localhost:8000/?lang=de
When lat
and lon
are passed, the records that have a location filter set will be returned only if the point defined by lat
and lon
is within record's location.
Accepted values: ESPG:4326
latitude and longitude
Example call: http://localhost:8000/?lat=44.5&lon=9.23
This project is licensed under the GPL-2.0 License. See the COPYING file for details.
qgis-feed/
βββ π‘οΈ config/ # Nginx configuration files
βββ πΌοΈ img/ # Images and media assets for this README
βββ π qgisfeedproject/ # Main Django project source code
βββ π οΈ scripts/ # Utility and deployment scripts (eg. renew_ssl.sh)
βββ π COPYING # Project license (GPL-2.0)
βββ π³ docker-compose-production-ssl.yml # Docker Compose config for production with SSL
βββ π³ docker-compose-production.yml # Docker Compose config for production
βββ π§ͺ docker-compose-testing.yml # Docker Compose config for testing
βββ π οΈ docker-compose.dev.yml # Docker Compose config for development
βββ π³ Dockerfile # Main Docker build instructions
βββ π³ Dockerfile.nginx.production # Dockerfile for Nginx in production
βββ π³ Dockerfile.production # Dockerfile for production app container
βββ π§ͺ Dockerfile.testing # Dockerfile for testing environment
βββ π entrypoint_production.sh # Entrypoint script for production container
βββ π entrypoint_testing.sh # Entrypoint script for testing container
βββ π env.template # Example environment variables file
βββ π MAKE_COMMANDS.md # Documentation for Makefile commands
βββ π οΈ Makefile # Common development and deployment commands
βββ π¦ package.json # Node.js dependencies and scripts
βββ π README.md # Project documentation
βββ π REQUIREMENTS.txt # Python dependencies for development
βββ π REQUIREMENTS_PRODUCTION.txt # Python dependencies for production
βββ βοΈ settings_docker_production.py # Django settings for Docker production
βββ βοΈ settings_docker_testing.py # Django settings for Docker testing
βββ βοΈ shell.nix # Nix shell environment for development
βββ π» vscode.sh # VSCode helper script for Nix shell environment
βββ π list-vscode-extensions.sh # Script to list VSCode extensions for Nix shell environment
βββ βοΈ webpack.config.js # Webpack configuration
We are fine with using LLM's and Generative Machine Learning to act as general assistants, but the following three guidelines should be followed:
- Repeatability: Although we understand that repeatability is not possible generally, whenever you are verbatim using LLM or Generative Machine Learning outputs in this project, you must also provide the prompt that you used to generate the resource.
- Declaration: Sharing the prompt above is implicit declaration that a machine learning assistant was used. If it is not obvious that a piece of work was generated, include the robot (π€) icon next to a code snippet or text snippet.
- Validation: Outputs generated by a virtual assistant should always be validated by a human and you, as contributor, take ultimate responsibility for the correct functionality of any code and the correct expression in any text or media you submit to this project.
This application is based on Django, written in Python and deployed on the server using docker-compose.
Below is the Entity-Relationship Diagram (ERD) illustrating the core data model for the QGIS Feed Website. For a detailed view, click on the image below or see the full-size diagram in erd.svg:
Please refer to the Nix section in CONTRIBUTING.md.
We welcome contributions! Please read the CONTRIBUTING.md for guidelines on how to get started.
Have questions or feedback? Feel free to open an issue or submit a Pull Request!
- Tim Sutton β Original author and lead maintainer of the QGIS Feed Website project
- Kontur Team β Responsible for the design of the current theme
- Lova Andriarimalala β Core developer and ongoing maintainer
- QGIS Contributors β See the full list of amazing contributors who have helped make this website possible.
Made with β€οΈ by Tim Sutton (@timlinux), Lova Andriarimalala (@Xpirix) and QGIS Contributors.