{"id":20509065,"url":"https://github.com/abeluck/mod_monthly_visitors","last_synced_at":"2026-05-21T16:07:36.128Z","repository":{"id":146550519,"uuid":"133491168","full_name":"abeluck/mod_monthly_visitors","owner":"abeluck","description":null,"archived":false,"fork":false,"pushed_at":"2018-05-21T17:14:58.000Z","size":3,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-01-16T08:28:22.062Z","etag":null,"topics":["lua","prosody-module"],"latest_commit_sha":null,"homepage":null,"language":"Lua","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/abeluck.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-05-15T09:15:02.000Z","updated_at":"2018-09-20T12:50:53.000Z","dependencies_parsed_at":"2023-06-04T18:30:28.057Z","dependency_job_id":null,"html_url":"https://github.com/abeluck/mod_monthly_visitors","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/abeluck%2Fmod_monthly_visitors","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/abeluck%2Fmod_monthly_visitors/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/abeluck%2Fmod_monthly_visitors/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/abeluck%2Fmod_monthly_visitors/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/abeluck","download_url":"https://codeload.github.com/abeluck/mod_monthly_visitors/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":242112151,"owners_count":20073539,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["lua","prosody-module"],"created_at":"2024-11-15T20:22:17.193Z","updated_at":"2026-05-21T16:07:31.081Z","avatar_url":"https://github.com/abeluck.png","language":"Lua","funding_links":[],"categories":[],"sub_categories":[],"readme":"---\nlabels:\n- 'Stage-Beta'\nsummary: Stores geoip and client of users aggregated on a monthly basis\n---\n\nDescription\n===========\n\nThe goal of this module is to store a few data points about users of the\nserver, but in a way that is privacy preserving.\n\nThis module stores monthly counts for two pieces of data about users on the\nserver:\n\n1. GeoIP location - the number of unique users per-month seen at a particular (Country, Subdivision, City) tuple.\n2. Client type - the number of unique users whose resource string match a certain regex pattern.\n\nAdditionally, a single year-month pair is stored on per-user basis that\nrepresents the last month the user was considered in the aggregate counts. This\nallows the module to only increment the counts for a user once per month.\n\nThe data is collected on first-login of the user in that month.\n\n#### Monthly totals data\n\nHere is an example of the collected data:\n\n```lua\n-- monthly-visitors.dat\nreturn {\n  [\"2018-05\"] = {\n    [\"geo-DE-HE-2925533\"] = 2;\n    [\"geo-AT-9-2761369\"] = 1;\n    [\"geo-US-TX-5525577\"] = 1;\n    [\"geo-CN-?-?\"] = 1;\n    [\"client-ANDROID\"] = 2;\n    [\"client-?\"] = 1;\n    [\"client-IOS\"] = 2;\n  };\n};\n```\n\nYou can see that data is keyed per month (`2018-05`), and there is a subkey per\nclient type and geo tuple.\n\nThe geo tuple is prefixed with `geo-` and is made up of three hyphen delimited\nparts: \n\n1. Country ISO code\n2. Subdivision ISO code\n3. City geoname id\n\nIf one of the parts is unknown it is marked as `?`.\n\nThe client data is prefixed with `client-` followed by the category as matched\nby the client patterns (see configuration section).\n\n##### Per-user data\n\nHere is an example of what is stored per-user:\n\n```lua\n-- monthly-visitors/username.dat \nreturn {\n  [\"last-recorded\"] = \"2018-05\";\n};\n```\n\nThat's it.\n\nInstallation\n============\n\nAs with all modules, copy it to your plugins directory and then add it to the\n`modules_enabled` list:\n\n```lua\nmodules_enabled = \n    -- ... other modules\n      \"monthly_visitors\",\n}\n```\n\n#### Dependencies\n\nThis module depends on:\n\n* [`mmdblua`][mmdblua] \u003e= 0.2 - reads the maxmind database format\n* [`compat53`][compat53]  \u003e= 0.3 - dependency of mmdblua (available in debian stretch as lua-compat53)\n\n#### GeoIP Database\n\nYou must have a geoip database in MaxMind DB format ([a free one\nis available][geoip]).\n\nPlace the `.mmdb` file somewhere on disk where prosody can read it, such as\n`/var/lib/prosody`. Be sure to chown it if necessary.\n\n\nConfiguration\n=============\n\n  Option                                   Default   Description\n  --------------------------------------   --------- ---------------------------------------------------------------------------------------------------------------\n  `mod_monthly_visitors_mmdb_path`         ``        The path to the GeoIp database in mmdb format.\n  `mod_monthly_visitors_client_patterns`   `{}`      A table of regex keys and client type values.\n  `mod_monthly_visitors_record_country`    `\"ALL\"`   A two-digit ISO code string for the country to capture stats for, or the special value `ALL` to log all countries.\n\nExample of `mod_monthly_visitors_client_patterns`:\n\n```lua\n\nlocal client_patterns = {};\nclient_patterns[\"^zom%d+.*\"] = \"IOS\";\nclient_patterns[\"^Zom-.*\"] = \"IOS\";\nclient_patterns[\"^chatsecure%d+.*\"] = \"IOS\";\nclient_patterns[\"^ChatSecureZom-.*\"] = \"ANDROID\";\nclient_patterns[\"^Conversations%..*\"] = \"ANDROID\";\n\nmod_monthly_visitors_client_patterns = client_patterns;\n\n```\n\nRoadmap\n=======\n\nIn the future I would like to add:\n\n* Automatic deletion of the aggregate stats after a certain date, or perhaps a\n  prosodyctl command for this.\n\nCompatibility\n=============\n\nTested on 0.10.0.\n\n[geoip]: https://dev.maxmind.com/geoip/geoip2/geolite2/\n[mmdblua]: https://github.com/daurnimator/mmdblua/releases\n[compat53]: https://github.com/keplerproject/lua-compat-5.3\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fabeluck%2Fmod_monthly_visitors","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fabeluck%2Fmod_monthly_visitors","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fabeluck%2Fmod_monthly_visitors/lists"}