{"id":17771759,"url":"https://github.com/jonnyburger/tics","last_synced_at":"2025-04-21T23:31:12.973Z","repository":{"id":38375724,"uuid":"153950340","full_name":"JonnyBurger/tics","owner":"JonnyBurger","description":"🎢 Simple self-hosted analytics ideal for Express / React Native stacks","archived":false,"fork":false,"pushed_at":"2023-01-20T04:01:56.000Z","size":1543,"stargazers_count":28,"open_issues_count":42,"forks_count":1,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-04-01T16:55:51.801Z","etag":null,"topics":["analytics","express","mongo","node","react-native","statistics"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","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/JonnyBurger.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}},"created_at":"2018-10-20T21:33:41.000Z","updated_at":"2024-12-19T18:36:00.000Z","dependencies_parsed_at":"2023-02-11T23:30:28.851Z","dependency_job_id":null,"html_url":"https://github.com/JonnyBurger/tics","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/JonnyBurger%2Ftics","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JonnyBurger%2Ftics/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JonnyBurger%2Ftics/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JonnyBurger%2Ftics/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/JonnyBurger","download_url":"https://codeload.github.com/JonnyBurger/tics/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250150662,"owners_count":21383207,"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":["analytics","express","mongo","node","react-native","statistics"],"created_at":"2024-10-26T21:36:48.090Z","updated_at":"2025-04-21T23:31:12.554Z","avatar_url":"https://github.com/JonnyBurger.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# 🎢  tics\n\u003e Simple self-hosted analytics ideal for Express / React Native stacks\n\n## 🚥 Install\n\nOn both your frontend and backend, install the tics library.\n\n```\nnpm i tics\n```\n\n## 🤹🏼‍  How it works\nYou mount an Express.js Router, accept requests to your server and save impressions in your database. `tics` also provides a frontend library to send impressions. \n\n## 🎛 Usage\n### Backend\n\n```js\nconst app = require('express');\nconst tics = require('tics/server');\nconst db = require('./mongo');\n\nconst {impressions, analytics, stats} = tics({\n    db: db.collection('impressions')\n});\n\n// Use endpoints to receive impressions and retrieve stats\napp.use('/telemetry', impressions);\napp.use('/analytics', mustBeAdmin, analytics);\n\n// Or use built-in functions to get stats\nawait stats.activeUsers.daily() // =\u003e 29\n```\n\n**tics()** takes a MongoDB database collection as an argument. Collections from `mongodb` and `then-mongo` drivers have been tested.\n\n**tics()** returns an object with 3 items:\n\n- `impressions` is an Express.js router that the frontend can call to collect telemetry data.\n- `analytics` is an Express.js router that exposes a JSON API with analytics data. You should add some middleware to protect this router with some sort of authentication.\n- `stats` is an object containing the following methods:\n    - `stats.dau()` returns daily active users\n    - `stats.wau()` returns weekly active users\n    - `stats.mau()` returns monthly active users\n    - `stats.userCount(filter)` counts users. You can add a mongo query to only count a subset of impressions.\n    - `stats.platforms()` returns a breakdown of the different platforms. Example response: `[{id: 'ios', count: 1000, id: 'android', count: 2000}]`\n    - `stats.languages()` returns a breakdown of the languages of the users devices. Example response: `[{id: 'de', count: 1000, id: 'en', count: 2000}]`\n    - `stats.versions()` returns a breakdown of the different versions of the app. Example response: `[{id: '1.0.0', count: 200}, {id: '1.0.1', count: 400}, {id: '1.1.0', count: 4000}]`\n    - `stats.contents()` returns a breakdown of the different contents that the analytics are tracking.\n    - `stats.breakDown()` allows to break down a custom field similar to the breakdowns above\n    - `stats.activityLevels` focus on breaking down the different interactions of one content.\n        - `stats.activityLevels.byContentType` returns a breakdown of the impressions of the different contents. Example: `[{id: 'register-screen', count: 1000}, {id: 'article-page', count: '100'}]`\n        - `stats.activityLevels.byContentId(content_id)` returns the breakdown of the different interactions with one entity of a content. Example reponse: `[{id: 'view', count: 20000, {id: 'click', count: 1000}, {id: 'conversion': 20}}]`,\n    - `stats.db` provides raw access to make queries yourself\n\n### Track from React Native / Expo / Web\n\n```ts\nimport tics from 'tics';\n\nconst analytics = tics({endpoint: 'https://jonny.io/api/telemetry'});\n\ntics.impression('https://jonny.io/api/telemetry', {\n    content: 'ad',\n    content_id: '3240978',\n    level: 'view',\n    platform: 'ios',\n    identifier: '098324',\n    language: 'de',\n    version: '1.0.0'\n})\n.then(() =\u003e { /* ... */})\n```\n\nPass as the `endpoint` parameter the URL where the `impressions` router is mounted. This is the host of your server plus the route of the impression router.\n\nReturned is an object which contains: \n\n- `impression`: Makes an impression request to the server. Terminology:\n    - `impression.content`: Type of content. For example `register-screen`, `ad`, `product`,\n    - `impression.content_id` *optional*: Allows to distinguish between different entities of the same content type.\n    - `impression.level`: Type of interaction. For example `view`/ `click`/ `conversion` for sales. Or `install` / `register` for tracking registration conversion. Default: `view`\n    - `impression.platform` *optional*: Operating system of the device. React native client will try to figure it out itself if this option is omitted.\n    - `impression.identifier` *optional*: Identifying string of the user. Multiple impressions by the same user get removed when calculating number of users. React native client will try to use native identifier when omitted.\n    - `impression.language` *optional*: Language of user's device\n    - `impression.version` *optional*: App version number. React Native client will try to find it when this parameter is omitted.\n    \n### Track sessions\n\nTrack sessions using React hooks. Pass a value for `isFocused` and it will automatically stop tracking if the user navigates away in React Native.\n\n```ts\nimport {useTics} from 'tics';\nimport {useIsFocused} from '@react-navigation/native';\n\nexport const Comp = () =\u003e {\n    const isFocused = useIsFocused();\n    useTics(isFocused, 'https://jonny.io/api/telemetry', {\n        content: 'ad',\n        content_id: '3240978',\n        level: 'view',\n        platform: 'ios',\n        identifier: '098324',\n        language: 'de',\n        version: '1.0.0'\n    })\n    return null;\n}\n```\n\n## 👨🏻‍💻 Author\n\n* [Jonny Burger](https://jonny.io)\n\n## 🗒 License\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjonnyburger%2Ftics","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjonnyburger%2Ftics","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjonnyburger%2Ftics/lists"}