{"_id":"@abdssamie/convex-analytics","_rev":"7-478680d0b392370bfda27406fd75bc57","name":"@abdssamie/convex-analytics","dist-tags":{"latest":"0.2.1"},"versions":{"0.1.0":{"name":"@abdssamie/convex-analytics","version":"0.1.0","keywords":["convex","component"],"license":"Apache-2.0","_id":"@abdssamie/convex-analytics@0.1.0","maintainers":[{"name":"abdessamie","email":"abdessamie.elmoubarki@gmail.com"}],"homepage":"https://github.com/Abdssamie/convex-analytics#readme","bugs":{"url":"https://github.com/Abdssamie/convex-analytics/issues"},"dist":{"shasum":"72b1110ef73b31316316aa60e24c708ddce91f35","tarball":"https://registry.npmjs.org/@abdssamie/convex-analytics/-/convex-analytics-0.1.0.tgz","fileCount":203,"integrity":"sha512-/iQ2bc1AngOs0vu/jo9/LbsEg/K7BgE3LqHaXn/qZ4zMufRDSjVOyoLe6DijxYsYbIrvB23qh/eIIokJTdiixQ==","signatures":[{"sig":"MEUCIQDGhGcEkdW39/WNVz1tdMO3EV2XaC2yU3eiYG32GrgijgIgEGMUVzm6LMmCHZ1dLDLxUjCbo4qCdVoukXlFeS2u4Bo=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":808246},"type":"module","types":"./dist/client/index.d.ts","module":"./dist/client/index.js","exports":{".":{"types":"./dist/client/index.d.ts","default":"./dist/client/index.js"},"./test":"./src/test.ts","./react":{"types":"./dist/react/index.d.ts","default":"./dist/react/index.js"},"./package.json":"./package.json","./convex.config":{"types":"./dist/component/convex.config.d.ts","default":"./dist/component/convex.config.js"},"./convex.config.js":{"types":"./dist/component/convex.config.d.ts","default":"./dist/component/convex.config.js"},"./_generated/component":{"types":"./dist/component/_generated/component.d.ts"},"./_generated/component.js":{"types":"./dist/component/_generated/component.d.ts"}},"gitHead":"2b42473211176efae0fd8f20cf6a85a40f400e8e","scripts":{"dev":"convex dev --run example:setupDefaultSite --start 'npm run dev:build'","lint":"oxlint .","test":"vitest run --typecheck","alpha":"npm version prerelease --preid alpha && npm publish --tag alpha && git push --follow-tags","build":"tsc --build ./tsconfig.build.json --force","predev":"convex init && npm run build:codegen","perf:k6":"k6 run perf/k6/analytics-ingest.js","release":"npm version patch && npm publish && git push --follow-tags","version":"(npm whoami || npm login) && vim -c 'normal o' -c 'normal o## '$npm_package_version CHANGELOG.md && prettier -w CHANGELOG.md && git add CHANGELOG.md","dev:build":"chokidar 'tsconfig*.json' 'src/**/*.ts' -i '**/*.test.ts' -c 'npm run build:codegen' --initial","typecheck":"tsc --noEmit && tsc -p example && tsc -p example/convex","preversion":"npm ci && npm run build:clean && npm run test && npm run lint && npm run typecheck","test:debug":"vitest --inspect-brk --no-file-parallelism","test:watch":"vitest --typecheck --clearScreen false","build:clean":"rm -rf dist *.tsbuildinfo && npm run build:codegen","dev:frontend":"cd example && vite","build:codegen":"npx convex codegen --component-dir ./src/component && npm run build","test:coverage":"vitest run --coverage --coverage.reporter=text","perf:playwright":"playwright test -c playwright.load.config.ts"},"_npmUser":{"name":"abdessamie","email":"abdessamie.elmoubarki@gmail.com"},"repository":{"url":"git+https://github.com/Abdssamie/convex-analytics.git","type":"git"},"_npmVersion":"11.9.0","description":"A convex analytics component for Convex.","directories":{},"_nodeVersion":"24.14.0","_hasShrinkwrap":false,"devDependencies":{"vite":"7.3.2","react":"^19.2.5","convex":"1.35.1","oxlint":"^1.60.0","vitest":"4.1.4","prettier":"3.8.2","react-dom":"^19.2.5","pkg-pr-new":"^0.0.66","typescript":"5.9.3","@types/node":"^24.12.2","convex-test":"0.0.47","@types/react":"^19.2.14","chokidar-cli":"3.0.0","@edge-runtime/vm":"^5.0.0","@playwright/test":"^1.55.0","@types/react-dom":"^19.2.3","@vitejs/plugin-react":"^5.2.0"},"peerDependencies":{"react":"^18.3.1 || ^19.0.0","convex":"^1.35.1"},"_npmOperationalInternal":{"tmp":"tmp/convex-analytics_0.1.0_1777055021214_0.37978788294834853","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"@abdssamie/convex-analytics","version":"0.1.1","keywords":["convex","component"],"license":"Apache-2.0","_id":"@abdssamie/convex-analytics@0.1.1","maintainers":[{"name":"abdessamie","email":"abdessamie.elmoubarki@gmail.com"}],"homepage":"https://github.com/Abdssamie/convex-analytics#readme","bugs":{"url":"https://github.com/Abdssamie/convex-analytics/issues"},"dist":{"shasum":"6fd7b242e0a5a073db3719654570ad3bfc94f0e1","tarball":"https://registry.npmjs.org/@abdssamie/convex-analytics/-/convex-analytics-0.1.1.tgz","fileCount":203,"integrity":"sha512-hHER5lUMlnhjIlaHHn3DI/dHGjnI7WYxhsR9dkSsswoyttZ57EKmaDPj0tAsJ9tu6jp6NKhWKxhWJ3bUcc4ghw==","signatures":[{"sig":"MEQCIF853eGBBYazUmOl3IOmhDsJj1yTetn2qs4nvK/mk+5yAiAxYgLxHnorWzuc0TIcQzOAcnGMHld/FTHhYDAE/jhaVw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":815379},"type":"module","types":"./dist/client/index.d.ts","module":"./dist/client/index.js","exports":{".":{"types":"./dist/client/index.d.ts","default":"./dist/client/index.js"},"./test":"./src/test.ts","./react":{"types":"./dist/react/index.d.ts","default":"./dist/react/index.js"},"./package.json":"./package.json","./convex.config":{"types":"./dist/component/convex.config.d.ts","default":"./dist/component/convex.config.js"},"./convex.config.js":{"types":"./dist/component/convex.config.d.ts","default":"./dist/component/convex.config.js"},"./_generated/component":{"types":"./dist/component/_generated/component.d.ts"},"./_generated/component.js":{"types":"./dist/component/_generated/component.d.ts"}},"gitHead":"194d03b86886789b129367cc2e709d154fe7ef99","scripts":{"dev":"convex dev --run example:setupDefaultSite --start 'npm run dev:build'","lint":"oxlint .","test":"vitest run --typecheck","alpha":"npm version prerelease --preid alpha && npm publish --tag alpha && git push --follow-tags","build":"tsc --build ./tsconfig.build.json --force","predev":"convex init && npm run build:codegen","perf:k6":"k6 run perf/k6/analytics-ingest.js","release":"npm version patch && npm publish && git push --follow-tags","version":"prettier -w CHANGELOG.md && git add CHANGELOG.md","dev:build":"chokidar 'tsconfig*.json' 'src/**/*.ts' -i '**/*.test.ts' -c 'npm run build:codegen' --initial","typecheck":"tsc --noEmit && tsc -p example && tsc -p example/convex","preversion":"npm ci && npm run build:clean && npm run test && npm run lint && npm run typecheck","test:debug":"vitest --inspect-brk --no-file-parallelism","test:watch":"vitest --typecheck --clearScreen false","build:clean":"rm -rf dist *.tsbuildinfo && npm run build:codegen","dev:frontend":"cd example && vite","build:codegen":"npx convex codegen --component-dir ./src/component && npm run build","test:coverage":"vitest run --coverage --coverage.reporter=text","prepublishOnly":"npm run build:clean","verify:release":"npm run build:clean && npm run lint && npm run typecheck && npm test && npm pack","perf:playwright":"playwright test -c playwright.load.config.ts"},"_npmUser":{"name":"abdessamie","email":"abdessamie.elmoubarki@gmail.com"},"repository":{"url":"git+https://github.com/Abdssamie/convex-analytics.git","type":"git"},"_npmVersion":"11.9.0","description":"A convex analytics component for Convex.","directories":{},"_nodeVersion":"24.14.0","_hasShrinkwrap":false,"devDependencies":{"vite":"7.3.2","react":"^19.2.5","convex":"1.35.1","oxlint":"^1.60.0","vitest":"4.1.4","prettier":"3.8.2","react-dom":"^19.2.5","pkg-pr-new":"^0.0.66","typescript":"5.9.3","@types/node":"^24.12.2","convex-test":"0.0.47","@types/react":"^19.2.14","chokidar-cli":"3.0.0","@edge-runtime/vm":"^5.0.0","@playwright/test":"^1.55.0","@types/react-dom":"^19.2.3","@vitejs/plugin-react":"^5.2.0"},"peerDependencies":{"react":"^18.3.1 || ^19.0.0","convex":"^1.35.1"},"_npmOperationalInternal":{"tmp":"tmp/convex-analytics_0.1.1_1777056969000_0.5849297707217884","host":"s3://npm-registry-packages-npm-production"}},"0.1.2":{"name":"@abdssamie/convex-analytics","version":"0.1.2","keywords":["convex","component"],"license":"Apache-2.0","_id":"@abdssamie/convex-analytics@0.1.2","maintainers":[{"name":"abdessamie","email":"abdessamie.elmoubarki@gmail.com"}],"homepage":"https://github.com/Abdssamie/convex-analytics#readme","bugs":{"url":"https://github.com/Abdssamie/convex-analytics/issues"},"dist":{"shasum":"20a6c0da2d15834f24d0ea6fd420e4b2ac9f7c60","tarball":"https://registry.npmjs.org/@abdssamie/convex-analytics/-/convex-analytics-0.1.2.tgz","fileCount":210,"integrity":"sha512-EJZvKRdIQPcMJlO5cQdLHO9SrKuLBOrvHCN0srCp1q3Ixb/Vx9r2zFdG258CiVcufjpBnvOmOsIURDN1y2ypQQ==","signatures":[{"sig":"MEQCIBcJG8PSRbOYcqy3IDiFq0isS7MK6nSIKzMMPJL9tHHeAiAsZBvf9SCo9+yGAzHBxhN6Lmbt6Xty4QLsi0rjIW3M4w==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":852698},"type":"module","types":"./dist/client/index.d.ts","unpkg":"./dist/embed/convex-analytics.js","module":"./dist/client/index.js","exports":{".":{"types":"./dist/client/index.d.ts","default":"./dist/client/index.js"},"./test":"./src/test.ts","./embed":"./dist/embed/convex-analytics.js","./react":{"types":"./dist/react/index.d.ts","default":"./dist/react/index.js"},"./embed.js":"./dist/embed/convex-analytics.js","./package.json":"./package.json","./convex.config":{"types":"./dist/component/convex.config.d.ts","default":"./dist/component/convex.config.js"},"./convex.config.js":{"types":"./dist/component/convex.config.d.ts","default":"./dist/component/convex.config.js"},"./_generated/component":{"types":"./dist/component/_generated/component.d.ts"},"./_generated/component.js":{"types":"./dist/component/_generated/component.d.ts"}},"gitHead":"e973f4fc0eb918b3c9d92e5f6f7d91886509ffa1","scripts":{"dev":"convex dev --run example:setupDefaultSite --start 'npm run dev:build'","lint":"oxlint .","test":"vitest run --typecheck","alpha":"npm version prerelease --preid alpha && npm publish --tag alpha && git push --follow-tags","build":"tsc --build ./tsconfig.build.json --force","predev":"convex init && npm run build:codegen","perf:k6":"k6 run perf/k6/analytics-ingest.js","release":"npm version patch && npm publish && git push --follow-tags","version":"prettier -w CHANGELOG.md && git add CHANGELOG.md","dev:build":"chokidar 'tsconfig*.json' 'src/**/*.ts' -i '**/*.test.ts' -c 'npm run build:codegen' --initial","typecheck":"tsc --noEmit && tsc -p example && tsc -p example/convex","preversion":"npm ci && npm run build:clean && npm run test && npm run lint && npm run typecheck","test:debug":"vitest --inspect-brk --no-file-parallelism","test:watch":"vitest --typecheck --clearScreen false","build:clean":"rm -rf dist *.tsbuildinfo && npm run build:codegen && npm run build:embed","build:embed":"node scripts/build-embed.mjs","dev:frontend":"cd example && vite","build:codegen":"npx convex codegen --component-dir ./src/component && npm run build","test:coverage":"vitest run --coverage --coverage.reporter=text","prepublishOnly":"npm run build:clean","verify:release":"npm run build:clean && npm run lint && npm run typecheck && npm test && npm pack","perf:playwright":"playwright test -c playwright.load.config.ts"},"_npmUser":{"name":"abdessamie","email":"abdessamie.elmoubarki@gmail.com"},"jsdelivr":"./dist/embed/convex-analytics.js","repository":{"url":"git+https://github.com/Abdssamie/convex-analytics.git","type":"git"},"_npmVersion":"11.9.0","description":"A convex analytics component for Convex.","directories":{},"_nodeVersion":"24.14.0","_hasShrinkwrap":false,"devDependencies":{"vite":"7.3.2","react":"^19.2.5","convex":"1.35.1","oxlint":"^1.60.0","vitest":"4.1.4","prettier":"3.8.2","react-dom":"^19.2.5","pkg-pr-new":"^0.0.66","typescript":"5.9.3","@types/node":"^24.12.2","convex-test":"0.0.47","@types/react":"^19.2.14","chokidar-cli":"3.0.0","@edge-runtime/vm":"^5.0.0","@playwright/test":"^1.55.0","@types/react-dom":"^19.2.3","@vitejs/plugin-react":"^5.2.0"},"peerDependencies":{"react":"^18.3.1 || ^19.0.0","convex":"^1.35.1"},"_npmOperationalInternal":{"tmp":"tmp/convex-analytics_0.1.2_1777061930898_0.5362491770441598","host":"s3://npm-registry-packages-npm-production"}},"0.1.4":{"name":"@abdssamie/convex-analytics","version":"0.1.4","keywords":["convex","component"],"license":"Apache-2.0","_id":"@abdssamie/convex-analytics@0.1.4","maintainers":[{"name":"abdessamie","email":"abdessamie.elmoubarki@gmail.com"}],"homepage":"https://github.com/Abdssamie/convex-analytics#readme","bugs":{"url":"https://github.com/Abdssamie/convex-analytics/issues"},"dist":{"shasum":"6a5e10979255d824ceef4f7fc1642237e300f07d","tarball":"https://registry.npmjs.org/@abdssamie/convex-analytics/-/convex-analytics-0.1.4.tgz","fileCount":210,"integrity":"sha512-qcOei3IyGnT2ATJ+RBku2TNmuqMvrxt6YXJPFtDYACbzJt4BCoiMtHtChi0G6I8pXx/qPv+gTQAxCaK29lnqlQ==","signatures":[{"sig":"MEUCIQD7f7n7cuTzzW6HDzh5CNMKHeEJU2rojKjym88EmTqsfQIgM6Bfm/WxBEWk3QfAXLgLKg5ZBsv5mpcXk68iLHJSFP0=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":875848},"type":"module","types":"./dist/client/index.d.ts","unpkg":"./dist/embed/convex-analytics.js","module":"./dist/client/index.js","exports":{".":{"types":"./dist/client/index.d.ts","default":"./dist/client/index.js"},"./test":"./src/test.ts","./embed":"./dist/embed/convex-analytics.js","./react":{"types":"./dist/react/index.d.ts","default":"./dist/react/index.js"},"./embed.js":"./dist/embed/convex-analytics.js","./package.json":"./package.json","./convex.config":{"types":"./dist/component/convex.config.d.ts","default":"./dist/component/convex.config.js"},"./convex.config.js":{"types":"./dist/component/convex.config.d.ts","default":"./dist/component/convex.config.js"},"./_generated/component":{"types":"./dist/component/_generated/component.d.ts"},"./_generated/component.js":{"types":"./dist/component/_generated/component.d.ts"}},"gitHead":"6287bdcf8cde03e7f6d22f416e1612d0c3c4ce1d","scripts":{"dev":"convex dev --run example:setupDefaultSite --start 'npm run dev:build'","lint":"oxlint .","test":"vitest run --typecheck","alpha":"npm version prerelease --preid alpha && npm publish --tag alpha && git push --follow-tags","build":"tsc --build ./tsconfig.build.json --force","predev":"convex init && npm run build:codegen","perf:k6":"k6 run perf/k6/analytics-ingest.js","release":"npm version patch && npm publish && git push --follow-tags","version":"prettier -w CHANGELOG.md && git add CHANGELOG.md","dev:build":"chokidar 'tsconfig*.json' 'src/**/*.ts' -i '**/*.test.ts' -c 'npm run build:codegen' --initial","typecheck":"tsc --noEmit && tsc -p example && tsc -p example/convex","preversion":"npm ci && npm run build:clean && npm run test && npm run lint && npm run typecheck","test:debug":"vitest --inspect-brk --no-file-parallelism","test:watch":"vitest --typecheck --clearScreen false","build:clean":"rm -rf dist *.tsbuildinfo && npm run build:codegen && npm run build:embed","build:embed":"node scripts/build-embed.mjs","dev:frontend":"cd example && vite","build:codegen":"npx convex codegen --component-dir ./src/component && npm run build","test:coverage":"vitest run --coverage --coverage.reporter=text","prepublishOnly":"npm run build:clean","verify:release":"npm run build:clean && npm run lint && npm run typecheck && npm test && npm pack","perf:playwright":"playwright test -c playwright.load.config.ts"},"_npmUser":{"name":"abdessamie","email":"abdessamie.elmoubarki@gmail.com"},"jsdelivr":"./dist/embed/convex-analytics.js","repository":{"url":"git+https://github.com/Abdssamie/convex-analytics.git","type":"git"},"_npmVersion":"11.9.0","description":"A convex analytics component for Convex.","directories":{},"_nodeVersion":"24.14.0","_hasShrinkwrap":false,"devDependencies":{"vite":"7.3.2","react":"^19.2.5","convex":"1.35.1","oxlint":"^1.60.0","vitest":"4.1.4","prettier":"3.8.2","react-dom":"^19.2.5","pkg-pr-new":"^0.0.66","typescript":"5.9.3","@types/node":"^24.12.2","convex-test":"0.0.47","@types/react":"^19.2.14","chokidar-cli":"3.0.0","@edge-runtime/vm":"^5.0.0","@playwright/test":"^1.55.0","@types/react-dom":"^19.2.3","@vitejs/plugin-react":"^5.2.0"},"peerDependencies":{"react":"^18.3.1 || ^19.0.0","convex":"^1.35.1"},"_npmOperationalInternal":{"tmp":"tmp/convex-analytics_0.1.4_1777065419722_0.17630821121896756","host":"s3://npm-registry-packages-npm-production"}},"0.1.5":{"name":"@abdssamie/convex-analytics","version":"0.1.5","keywords":["convex","component"],"license":"Apache-2.0","_id":"@abdssamie/convex-analytics@0.1.5","maintainers":[{"name":"abdessamie","email":"abdessamie.elmoubarki@gmail.com"}],"homepage":"https://github.com/Abdssamie/convex-analytics#readme","bugs":{"url":"https://github.com/Abdssamie/convex-analytics/issues"},"dist":{"shasum":"45d702d897b54491bdf0a46305bfb9ff3a08f808","tarball":"https://registry.npmjs.org/@abdssamie/convex-analytics/-/convex-analytics-0.1.5.tgz","fileCount":210,"integrity":"sha512-GzbQoFOOroV65hhNdKkCt7GwYIQzoVhBrVbK98cHu+1nUN7veRr4/PYUWdyarJvLfgpRLpbFc5NKmro/4tzmjg==","signatures":[{"sig":"MEYCIQDYK1xki5rASxPeQNuoLQmL/yD6sBDGddzBuiMy5QkNiwIhAOCyMDr3G8Sj5L8F+4a67V14vAGOnwGPARZ4uKau5USX","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":875848},"type":"module","types":"./dist/client/index.d.ts","unpkg":"./dist/embed/convex-analytics.js","module":"./dist/client/index.js","exports":{".":{"types":"./dist/client/index.d.ts","default":"./dist/client/index.js"},"./test":"./src/test.ts","./embed":"./dist/embed/convex-analytics.js","./react":{"types":"./dist/react/index.d.ts","default":"./dist/react/index.js"},"./embed.js":"./dist/embed/convex-analytics.js","./package.json":"./package.json","./convex.config":{"types":"./dist/component/convex.config.d.ts","default":"./dist/component/convex.config.js"},"./convex.config.js":{"types":"./dist/component/convex.config.d.ts","default":"./dist/component/convex.config.js"},"./_generated/component":{"types":"./dist/component/_generated/component.d.ts"},"./_generated/component.js":{"types":"./dist/component/_generated/component.d.ts"}},"gitHead":"d7a97492c30888e37100dacbff3fabb89f494a75","scripts":{"dev":"convex dev --run example:setupDefaultSite --start 'npm run dev:build'","lint":"oxlint .","test":"vitest run --typecheck","alpha":"npm version prerelease --preid alpha && npm publish --tag alpha && git push --follow-tags","build":"tsc --build ./tsconfig.build.json --force","predev":"convex init && npm run build:codegen","perf:k6":"k6 run perf/k6/analytics-ingest.js","release":"npm version patch && npm publish && git push --follow-tags","version":"prettier -w CHANGELOG.md && git add CHANGELOG.md","dev:build":"chokidar 'tsconfig*.json' 'src/**/*.ts' -i '**/*.test.ts' -c 'npm run build:codegen' --initial","typecheck":"tsc --noEmit && tsc -p example && tsc -p example/convex","preversion":"npm ci && npm run build:clean && npm run test && npm run lint && npm run typecheck","test:debug":"vitest --inspect-brk --no-file-parallelism","test:watch":"vitest --typecheck --clearScreen false","build:clean":"rm -rf dist *.tsbuildinfo && npm run build:codegen && npm run build:embed","build:embed":"node scripts/build-embed.mjs","dev:frontend":"cd example && vite","build:codegen":"npx convex codegen --component-dir ./src/component && npm run build","test:coverage":"vitest run --coverage --coverage.reporter=text","prepublishOnly":"npm run build:clean","verify:release":"npm run build:clean && npm run lint && npm run typecheck && npm test && npm pack","perf:playwright":"playwright test -c playwright.load.config.ts"},"_npmUser":{"name":"abdessamie","email":"abdessamie.elmoubarki@gmail.com"},"jsdelivr":"./dist/embed/convex-analytics.js","repository":{"url":"git+https://github.com/Abdssamie/convex-analytics.git","type":"git"},"_npmVersion":"11.9.0","description":"A convex analytics component for Convex.","directories":{},"_nodeVersion":"24.14.0","_hasShrinkwrap":false,"devDependencies":{"vite":"7.3.2","react":"^19.2.5","convex":"1.35.1","oxlint":"^1.60.0","vitest":"4.1.4","prettier":"3.8.2","react-dom":"^19.2.5","pkg-pr-new":"^0.0.66","typescript":"5.9.3","@types/node":"^24.12.2","convex-test":"0.0.47","@types/react":"^19.2.14","chokidar-cli":"3.0.0","@edge-runtime/vm":"^5.0.0","@playwright/test":"^1.55.0","@types/react-dom":"^19.2.3","@vitejs/plugin-react":"^5.2.0"},"peerDependencies":{"react":"^18.3.1 || ^19.0.0","convex":"^1.35.1"},"_npmOperationalInternal":{"tmp":"tmp/convex-analytics_0.1.5_1777065691163_0.45527189957367753","host":"s3://npm-registry-packages-npm-production"}},"0.1.6":{"name":"@abdssamie/convex-analytics","version":"0.1.6","keywords":["convex","component"],"license":"Apache-2.0","_id":"@abdssamie/convex-analytics@0.1.6","maintainers":[{"name":"abdessamie","email":"abdessamie.elmoubarki@gmail.com"}],"homepage":"https://github.com/Abdssamie/convex-analytics#readme","bugs":{"url":"https://github.com/Abdssamie/convex-analytics/issues"},"dist":{"shasum":"1145ef874c5aa89cba14828bcdb800e1cc684827","tarball":"https://registry.npmjs.org/@abdssamie/convex-analytics/-/convex-analytics-0.1.6.tgz","fileCount":210,"integrity":"sha512-lxsN+UWV0Pajc4ZmeR/ZFGJgaKm8JRuvsTDVUL2988/pHtFZOjQu8zQ90+vvPPCVwG/IRgoLuVwqmBwKD6l0vw==","signatures":[{"sig":"MEQCIEo4b+mpkVw/HAOvY/etk6OODkxadoK3DyLl2qPZbdNkAiAqH/jTRbLwCnMfc6wgJOgM/3krDOc7by+gVJD5F8SdQw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":875850},"type":"module","types":"./dist/client/index.d.ts","unpkg":"./dist/embed/convex-analytics.js","module":"./dist/client/index.js","exports":{".":{"types":"./dist/client/index.d.ts","default":"./dist/client/index.js"},"./test":"./src/test.ts","./embed":"./dist/embed/convex-analytics.js","./react":{"types":"./dist/react/index.d.ts","default":"./dist/react/index.js"},"./embed.js":"./dist/embed/convex-analytics.js","./package.json":"./package.json","./convex.config":{"types":"./dist/component/convex.config.d.ts","default":"./dist/component/convex.config.js"},"./convex.config.js":{"types":"./dist/component/convex.config.d.ts","default":"./dist/component/convex.config.js"},"./_generated/component":{"types":"./dist/component/_generated/component.d.ts"},"./_generated/component.js":{"types":"./dist/component/_generated/component.d.ts"}},"gitHead":"8dd6df8db181e09f8b815005f6d7c256172a00a0","scripts":{"dev":"convex dev --run example:setupDefaultSite --start 'npm run dev:build'","lint":"oxlint .","test":"vitest run --typecheck","alpha":"npm version prerelease --preid alpha && npm publish --tag alpha && git push --follow-tags","build":"tsc --build ./tsconfig.build.json --force","predev":"convex init && npm run build:codegen","perf:k6":"k6 run perf/k6/analytics-ingest.js","release":"npm version patch && npm publish && git push --follow-tags","version":"prettier -w CHANGELOG.md && git add CHANGELOG.md","dev:build":"chokidar 'tsconfig*.json' 'src/**/*.ts' -i '**/*.test.ts' -c 'npm run build:codegen' --initial","typecheck":"tsc --noEmit && tsc -p example && tsc -p example/convex","preversion":"npm ci && npm run build:clean && npm run test && npm run lint && npm run typecheck","test:debug":"vitest --inspect-brk --no-file-parallelism","test:watch":"vitest --typecheck --clearScreen false","build:clean":"rm -rf dist *.tsbuildinfo && npm run build:codegen && npm run build:embed","build:embed":"node scripts/build-embed.mjs","dev:frontend":"cd example && vite","build:codegen":"npx convex codegen --component-dir ./src/component && npm run build","test:coverage":"vitest run --coverage --coverage.reporter=text","prepublishOnly":"npm run build:clean","verify:release":"npm run build:clean && npm run lint && npm run typecheck && npm test && npm pack","perf:playwright":"playwright test -c playwright.load.config.ts"},"_npmUser":{"name":"abdessamie","email":"abdessamie.elmoubarki@gmail.com"},"jsdelivr":"./dist/embed/convex-analytics.js","repository":{"url":"git+https://github.com/Abdssamie/convex-analytics.git","type":"git"},"_npmVersion":"11.9.0","description":"A convex analytics component for Convex.","directories":{},"_nodeVersion":"24.14.0","_hasShrinkwrap":false,"devDependencies":{"vite":"7.3.2","react":"^19.2.5","convex":"1.35.1","oxlint":"^1.60.0","vitest":"4.1.4","prettier":"3.8.2","react-dom":"^19.2.5","pkg-pr-new":"^0.0.66","typescript":"5.9.3","@types/node":"^24.12.2","convex-test":"0.0.47","@types/react":"^19.2.14","chokidar-cli":"3.0.0","@edge-runtime/vm":"^5.0.0","@playwright/test":"^1.55.0","@types/react-dom":"^19.2.3","@vitejs/plugin-react":"^5.2.0"},"peerDependencies":{"react":"^18.3.1 || ^19.0.0","convex":"^1.35.1"},"_npmOperationalInternal":{"tmp":"tmp/convex-analytics_0.1.6_1777065975410_0.718226014867603","host":"s3://npm-registry-packages-npm-production"}},"0.2.1":{"name":"@abdssamie/convex-analytics","description":"A convex analytics component for Convex.","repository":{"type":"git","url":"git+https://github.com/Abdssamie/convex-analytics.git"},"homepage":"https://github.com/Abdssamie/convex-analytics#readme","bugs":{"url":"https://github.com/Abdssamie/convex-analytics/issues"},"version":"0.2.1","license":"Apache-2.0","keywords":["convex","component"],"type":"module","unpkg":"./dist/embed/convex-analytics.js","jsdelivr":"./dist/embed/convex-analytics.js","exports":{"./package.json":"./package.json",".":{"types":"./dist/client/index.d.ts","default":"./dist/client/index.js"},"./embed":"./dist/embed/convex-analytics.js","./embed.js":"./dist/embed/convex-analytics.js","./react-native":{"types":"./dist/react-native/index.d.ts","default":"./dist/react-native/index.js"},"./react":{"types":"./dist/react/index.d.ts","default":"./dist/react/index.js"},"./test":"./src/test.ts","./_generated/component.js":{"types":"./dist/component/_generated/component.d.ts"},"./_generated/component":{"types":"./dist/component/_generated/component.d.ts"},"./convex.config.js":{"types":"./dist/component/convex.config.d.ts","default":"./dist/component/convex.config.js"},"./convex.config":{"types":"./dist/component/convex.config.d.ts","default":"./dist/component/convex.config.js"}},"peerDependencies":{"convex":"^1.35.1","react":"^18.3.1 || ^19.0.0"},"devDependencies":{"@edge-runtime/vm":"^5.0.0","@playwright/test":"^1.55.0","@types/node":"^24.12.2","@types/react":"^19.2.14","@types/react-dom":"^19.2.3","@vitejs/plugin-react":"^5.2.0","chokidar-cli":"3.0.0","convex":"1.35.1","convex-test":"0.0.47","oxlint":"^1.60.0","pkg-pr-new":"^0.0.66","prettier":"3.8.2","react":"^19.2.5","react-dom":"^19.2.5","typescript":"5.9.3","vite":"7.3.2","vitest":"4.1.4"},"types":"./dist/client/index.d.ts","module":"./dist/client/index.js","scripts":{"dev":"convex dev --run example:setupDefaultSite --start 'npm run dev:build'","dev:frontend":"cd example && vite","example:build":"cd example && vite build","dev:build":"chokidar 'tsconfig*.json' 'src/**/*.ts' -i '**/*.test.ts' -c 'npm run build:codegen' --initial","predev":"convex init && npm run build:codegen","build":"tsc --build ./tsconfig.build.json --force","build:embed":"node scripts/build-embed.mjs","build:codegen":"npx convex codegen --component-dir ./src/component && npm run build","build:clean":"rm -rf dist *.tsbuildinfo && npm run build:codegen && npm run build:embed","typecheck":"tsc --noEmit && tsc -p example && tsc -p example/convex","lint":"oxlint .","test":"vitest run --typecheck","test:watch":"vitest --typecheck --clearScreen false","test:debug":"vitest --inspect-brk --no-file-parallelism","test:coverage":"vitest run --coverage --coverage.reporter=text","perf:playwright":"playwright test -c playwright.load.config.ts","perf:k6":"k6 run perf/k6/analytics-ingest.js","verify:release":"npm run build:clean && npm run lint && npm run typecheck && npm test && npm pack","preversion":"npm ci && npm run build:clean && npm run test && npm run lint && npm run typecheck","alpha":"npm version prerelease --preid alpha && npm publish --tag alpha && git push --follow-tags","release":"npm version patch && npm publish && git push --follow-tags","version":"prettier -w CHANGELOG.md && git add CHANGELOG.md"},"_id":"@abdssamie/convex-analytics@0.2.1","_integrity":"sha512-gx4F8Z57dOcgiL9DbmyX5avIPw490FDrJAOud5eUSWl2oHBvLz/I1t0tJDS/EUNe25q1lMDINUmttUs6hdlHpw==","_resolved":"/tmp/de082ef1e0dd5d46ee426a1e39aa0729/abdssamie-convex-analytics-0.2.1.tgz","_from":"file:abdssamie-convex-analytics-0.2.1.tgz","_nodeVersion":"24.15.0","_npmVersion":"11.12.1","dist":{"integrity":"sha512-gx4F8Z57dOcgiL9DbmyX5avIPw490FDrJAOud5eUSWl2oHBvLz/I1t0tJDS/EUNe25q1lMDINUmttUs6hdlHpw==","shasum":"661ed30c15de0b6deeeafe0a0d6f4d9ef9f70476","tarball":"https://registry.npmjs.org/@abdssamie/convex-analytics/-/convex-analytics-0.2.1.tgz","fileCount":231,"unpackedSize":897807,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIHeFIEMCxWD0oucjBlv/oNPDPBOBXh1A35Zm7cbN4QmJAiAMftUfrv0NUmJcSXapYOtKDy/MgjUPSZRHM0ipaM+J4Q=="}]},"_npmUser":{"name":"abdessamie","email":"abdessamie.elmoubarki@gmail.com"},"directories":{},"maintainers":[{"name":"abdessamie","email":"abdessamie.elmoubarki@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/convex-analytics_0.2.1_1779215865825_0.4200965319809924"},"_hasShrinkwrap":false}},"time":{"created":"2026-04-24T18:23:41.069Z","modified":"2026-05-19T18:37:46.129Z","0.1.0":"2026-04-24T18:23:41.447Z","0.1.1":"2026-04-24T18:56:09.149Z","0.1.2":"2026-04-24T20:18:51.105Z","0.1.4":"2026-04-24T21:16:59.996Z","0.1.5":"2026-04-24T21:21:31.319Z","0.1.6":"2026-04-24T21:26:15.618Z","0.2.1":"2026-05-19T18:37:46.003Z"},"bugs":{"url":"https://github.com/Abdssamie/convex-analytics/issues"},"license":"Apache-2.0","homepage":"https://github.com/Abdssamie/convex-analytics#readme","keywords":["convex","component"],"repository":{"type":"git","url":"git+https://github.com/Abdssamie/convex-analytics.git"},"description":"A convex analytics component for Convex.","maintainers":[{"name":"abdessamie","email":"abdessamie.elmoubarki@gmail.com"}],"readme":"# Convex Analytics [![Convex Component](https://www.convex.dev/components/badge/abdssamie/convex-analytics)](https://www.convex.dev/components/abdssamie/convex-analytics)\nA first-party, real-time product analytics component for Convex. Track pageviews, custom events, and user identity directly into your own database—no third-party services required.\n\n- **Real-time Ingestion**: High-speed HTTP endpoint for event landing.\n- **Drop-in Dashboard**: A complete React component with timeseries charts and metrics.\n- **First-party Data**: You own the data; it stays in your Convex deployment.\n- **Browser SDK**: Tiny, dependency-free client with auto-batching.\n\n## Quick Start\n\n### Before you start: one write key, two places\n\nGenerate one write key for your site.\n\nYou will use that same raw key in two places:\n\n- server-side when creating the site\n- browser-side when sending ingest requests\n\nSuggested env vars:\n\n- Convex env: `ANALYTICS_WRITE_KEY`\n- frontend env: `NEXT_PUBLIC_ANALYTICS_WRITE_KEY` or `VITE_ANALYTICS_WRITE_KEY`\n\nIf those two values do not match, events will not be ingested.\n\n### 1. Install the Convex component\n\n```sh\nnpm install @abdssamie/convex-analytics\n```\n\n```ts\nimport { defineApp } from \"convex/server\";\nimport convexAnalytics from \"@abdssamie/convex-analytics/convex.config.js\";\n\nconst app = defineApp();\napp.use(convexAnalytics, { httpPrefix: \"/analytics-component/\" });\n\nexport default app;\n```\n\n### 2. Register the ingest route\n\n```ts\n// convex/http.ts\nimport { httpRouter } from \"convex/server\";\nimport { components } from \"./_generated/api\";\nimport { registerRoutes } from \"@abdssamie/convex-analytics\";\n\nconst http = httpRouter();\n\nregisterRoutes(http, components.convexAnalytics);\n\nexport default http;\n```\n\nIf `components.convexAnalytics` is missing, start your Convex dev server first\nso generated component bindings exist:\n\n```sh\nnpx convex dev\n```\n\n### 3. Create the default site once\n\nCreate a tiny bootstrap mutation:\n\n```ts\n// convex/analytics.ts\nimport { components } from \"./_generated/api\";\nimport { provisionSite } from \"@abdssamie/convex-analytics\";\n\nexport const provisionDefaultSite = provisionSite(components.convexAnalytics, {\n  auth: async () => {},\n  site: {\n    slug: \"default\",\n    name: \"Default site\",\n    writeKey: process.env.ANALYTICS_WRITE_KEY!,\n    allowedOrigins: [], // Don't forget allowed origins here to protect your service if key gets leaked\n  },\n});\n```\n\nThen run it once:\n\n```sh\nnpx convex run analytics:provisionDefaultSite\n```\n\n`provisionDefaultSite` is idempotent. If `default` already exists, nothing breaks.\nIt also fails fast if your analytics write key env var is missing or empty.\n\n### 4. Send events from the browser\n\n```ts\nimport { createAnalytics } from \"@abdssamie/convex-analytics\";\n\nconst analytics = createAnalytics({\n  endpoint: \"https://your-deployment.convex.site/analytics/ingest\",\n  writeKey: process.env.NEXT_PUBLIC_ANALYTICS_WRITE_KEY!,\n  autoPageviews: false,\n});\n\nanalytics.page();\nanalytics.track(\"signup_clicked\", { plan: \"pro\" });\nanalytics.identify(\"user_123\", { tier: \"pro\" });\n```\n\nThat is enough to start sending analytics.\n\nIf your app is not bundling npm modules, you can load the tracker with a plain\nscript tag instead of importing `createAnalytics(...)` directly.\n\nAuto-init with one script tag:\n\n```html\n<script\n  defer\n  src=\"https://unpkg.com/@abdssamie/convex-analytics@latest/dist/embed/convex-analytics.js\"\n  data-endpoint=\"https://your-deployment.convex.site/analytics/ingest\"\n  data-write-key=\"write_...\"\n  data-auto-pageviews=\"true\"\n></script>\n```\n\nOr initialize it manually:\n\n```html\n<script src=\"https://unpkg.com/@abdssamie/convex-analytics@latest/dist/embed/convex-analytics.js\"></script>\n<script>\n  window.ConvexAnalytics.init({\n    endpoint: \"https://your-deployment.convex.site/analytics/ingest\",\n    writeKey: \"write_...\",\n    autoPageviews: false,\n  });\n\n  window.ConvexAnalytics.page();\n</script>\n```\n\nAvailable browser globals:\n\n- `window.ConvexAnalytics.init(...)`\n- `window.ConvexAnalytics.page(...)`\n- `window.ConvexAnalytics.track(...)`\n- `window.ConvexAnalytics.identify(...)`\n- `window.ConvexAnalytics.flush()`\n\n### 5. Render the dashboard\n\nAfter the component and `default` site are set up, expose the read API from\nyour Convex backend and protect it with auth.\n\n### Backend: expose dashboard queries\n\n```ts\n// convex/analytics.ts\nimport { components } from \"./_generated/api\";\nimport {\n  exposeAdminApi,\n  exposeAnalyticsApi,\n} from \"@abdssamie/convex-analytics\";\n\nconst auth = async (ctx: { auth: { getUserIdentity: () => Promise<unknown> } }) => {\n  const identity = await ctx.auth.getUserIdentity();\n  if (!identity) {\n    throw new Error(\"Unauthorized\");\n  }\n};\n\nexport const { getSiteBySlug } = exposeAdminApi(components.convexAnalytics, {\n  auth: async (ctx) => auth(ctx),\n});\n\nexport const {\n  getDashboardSummary,\n  getOverview,\n  getTimeseries,\n  getTopPages,\n  getTopReferrers,\n  getTopSources,\n  getTopMediums,\n  getTopCampaigns,\n  getTopEvents,\n  getTopDevices,\n  getTopBrowsers,\n  getTopOs,\n  getTopCountries,\n  listRawEvents,\n  listPageviews,\n  listSessions,\n  listVisitors,\n} = exposeAnalyticsApi(components.convexAnalytics, {\n  auth: async (ctx, operation) => {\n    await auth(ctx);\n    // Add your own site ownership check here for operation.siteId.\n  },\n});\n```\n\n### Frontend: render the dashboard\n\n```tsx\nimport { AnalyticsDashboard } from \"@abdssamie/convex-analytics/react\";\nimport { useQuery } from \"convex/react\";\nimport { api } from \"../convex/_generated/api\";\n\nexport function DashboardPage() {\n  const site = useQuery(api.analytics.getSiteBySlug, { slug: \"default\" });\n\n  if (site === undefined) {\n    return <div>Loading...</div>;\n  }\n\n  if (site === null) {\n    return <div>Default analytics site not found.</div>;\n  }\n\n  return (\n    <AnalyticsDashboard\n      siteId={site._id}\n      api={{\n        getDashboardSummary: api.analytics.getDashboardSummary,\n        getOverview: api.analytics.getOverview,\n        getTimeseries: api.analytics.getTimeseries,\n        getTopPages: api.analytics.getTopPages,\n        getTopReferrers: api.analytics.getTopReferrers,\n        getTopSources: api.analytics.getTopSources,\n        getTopMediums: api.analytics.getTopMediums,\n        getTopCampaigns: api.analytics.getTopCampaigns,\n        getTopEvents: api.analytics.getTopEvents,\n        getTopDevices: api.analytics.getTopDevices,\n        getTopBrowsers: api.analytics.getTopBrowsers,\n        getTopOs: api.analytics.getTopOs,\n        getTopCountries: api.analytics.getTopCountries,\n        listRawEvents: api.analytics.listRawEvents,\n        listPageviews: api.analytics.listPageviews,\n        listSessions: api.analytics.listSessions,\n        listVisitors: api.analytics.listVisitors,\n      }}\n    />\n  );\n}\n```\n\nThe dashboard itself does not handle authentication. Auth belongs in your\nbackend wrappers, and the React component reads only from those authenticated\nqueries.\n\nComponent stores only `writeKeyHash`, not the raw write key.\n\nThe browser write key is an ingest credential, not an admin secret. Treat it like\na publishable key: make it long and random, restrict `allowedOrigins`, and rotate\nit if leaked.\n\n## What It Tracks\n\n- Pageviews\n- Custom product events\n- Anonymous visitors\n- Sessions\n- `identify(userId, traits)` links\n- Referrers and UTM campaign fields\n- Top pages, events, referrers, and campaigns\n- Overview and timeseries reports\n\n## Architecture\n\nThe component owns its own Convex tables:\n\n- `sites`: one tracked site/app per write key\n- `visitors`: durable anonymous visitor records\n- `sessions`: session windows and coarse device/browser/country summary\n- `events`: append-only raw events with lightweight aggregation marker\n- `rollups`: hourly/daily report counters\n\n```mermaid\nflowchart LR\n    Browser[\"Browser SDK / HTTP client\"] --> Http[\"HTTP ingest route\"]\n    Http --> Ingest[\"ingestBatch\\nappend-only raw event insert\"]\n    Ingest --> Events[(\"events\")]\n    Ingest --> Worker[\"reducePendingSiteEvents\"]\n    Worker --> Visitors[(\"visitors\")]\n    Worker --> Sessions[(\"sessions\")]\n    Worker --> Rollups[(\"rollups\\nhourly + daily\")]\n    Rollups --> Dashboard[\"Dashboard queries\\ngetOverview/getTimeseries/top lists\"]\n    Events --> Dashboard\n    Sessions --> Dashboard\n```\n\nWhy `sites` exists: one Convex deployment can track multiple sites or apps.\nFor the common one-site case, create one site named `default` and ignore the\nmulti-site parts until needed.\n\nBrowser traffic should use HTTP ingest route. Do not send every browser event\nthrough public Convex mutations. SDK batches events and HTTP route hashes write\nkey before calling component.\n\nIngest and reporting are split on purpose. `ingestBatch` writes raw events\nquickly, leaves `aggregatedAt: null`, and schedules background aggregation. The\nworker materializes visitors, sessions, and rollups, then stamps\n`aggregatedAt`.\n\nDashboard queries are range-aware:\n\n- overview and top-dimension queries use exact edge handling\n- first/last timeseries bucket is clipped to requested range\n- raw events can lag by worker time, usually a few seconds\n\n## Troubleshooting\n\n### Browser shows a CORS error on `/analytics/ingest`\n\nExample:\n\n```text\nAccess to fetch at 'https://your-deployment.convex.site/analytics/ingest'\nfrom origin 'http://localhost:3001' has been blocked by CORS policy:\nNo 'Access-Control-Allow-Origin' header is present on the requested resource.\n```\n\nCheck these first:\n\n- the browser is using the same write key you used in `provisionDefaultSite`\n- the site was created successfully\n- the current origin is allowed for that site\n\nWhy this looks like CORS:\n\n- the ingest route checks the write key and site before returning CORS headers\n- if that check fails, the browser often reports a generic CORS error\n\nUseful fixes:\n\n```sh\nnpx convex run analytics:provisionDefaultSite\n```\n\n- verify your frontend env var matches `ANALYTICS_WRITE_KEY`\n- verify `allowedOrigins` includes your local or production domain\n\n### `components.convexAnalytics` is missing\n\nRun your Convex dev server first so generated component bindings exist:\n\n```sh\nnpx convex dev\n```\n\n### Dashboard says the default site is not found\n\nYou registered the component and queries, but the site record does not exist yet.\nRun:\n\n```sh\nnpx convex run analytics:provisionDefaultSite\n```\n\n## Dashboard API\n\nWhen you want to read analytics in your app, expose only the read functions:\n\n```ts\n// convex/analytics.ts\nimport { components } from \"./_generated/api\";\nimport { exposeAnalyticsApi } from \"@abdssamie/convex-analytics\";\n\nexport const {\n  getDashboardSummary,\n  getOverview,\n  getTimeseries,\n  getEventPropertyBreakdown,\n  getTopPages,\n  getTopReferrers,\n  getTopSources,\n  getTopMediums,\n  getTopCampaigns,\n  getTopEvents,\n  getTopDevices,\n  getTopBrowsers,\n  getTopOs,\n  getTopCountries,\n  listRawEvents,\n  listPageviews,\n  listSessions,\n  listVisitors,\n} = exposeAnalyticsApi(components.convexAnalytics, {\n  auth: async (ctx, operation) => {\n    const identity = await ctx.auth.getUserIdentity();\n    if (!identity) {\n      throw new Error(\"Unauthorized\");\n    }\n    // Add your own site ownership check here for operation.siteId.\n  },\n});\n```\n\nDashboard surface:\n\n- `getDashboardSummary(siteId, from, to, interval)`\n- `getOverview(siteId, from, to)`\n- `getTimeseries(siteId, from, to, interval)`\n- `getEventPropertyBreakdown(siteId, eventName, propertyKey, from, to, limit?)`\n- `getTopPages(siteId, from, to, limit?)`\n- `getTopReferrers(siteId, from, to, limit?)`\n- `getTopSources(siteId, from, to, limit?)`\n- `getTopMediums(siteId, from, to, limit?)`\n- `getTopCampaigns(siteId, from, to, limit?)`\n- `getTopEvents(siteId, from, to, limit?)`\n- `getTopDevices(siteId, from, to, limit?)`\n- `getTopBrowsers(siteId, from, to, limit?)`\n- `getTopOs(siteId, from, to, limit?)`\n- `getTopCountries(siteId, from, to, limit?)`\n- `listRawEvents(siteId, from?, to?, paginationOpts)`\n- `listPageviews(siteId, from?, to?, paginationOpts)`\n- `listSessions(siteId, from?, to?, paginationOpts)`\n- `listVisitors(siteId, from?, to?, paginationOpts)`\n\n## Advanced: Site Admin API\n\nYou do not need this for the initial install.\n\nUse `exposeAdminApi(...)` only if your app needs site management:\n\n```ts\nimport { components } from \"./_generated/api\";\nimport { exposeAdminApi } from \"@abdssamie/convex-analytics\";\n\nexport const {\n  createSite,\n  updateSite,\n  rotateWriteKey,\n  cleanupSite,\n} = exposeAdminApi(components.convexAnalytics, {\n  auth: async (ctx, operation) => {\n    // admin auth / site ownership check here\n  },\n});\n```\n\nAdmin surface:\n\n- `createSite`, `updateSite`, `rotateWriteKey`\n- `cleanupSite(siteId? | slug?, now?, limit?, runUntilComplete?)`\n\nRecommended dashboard shape:\n\n1. `getOverview` for KPI cards\n2. `getTimeseries` for chart\n3. top-dimension queries for tables\n4. `getEventPropertyBreakdown` for lean product-event analysis\n5. `listRawEvents` / `listPageviews` / `listSessions` / `listVisitors` for drill-down/debug\n\nExample product analytics query:\n\n```ts\nawait ctx.runQuery(api.analytics.getEventPropertyBreakdown, {\n  siteId,\n  eventName: \"plan_selected\",\n  propertyKey: \"plan\",\n  from,\n  to,\n  limit: 10,\n});\n```\n\nRecommended event naming:\n\n- `track(\"plan_selected\", { plan: \"pro\" })`\n- `track(\"checkout_started\", { step: \"shipping\" })`\n- `identify(userId, { plan: \"pro\" })`\n\nDrill-down queries return Convex pagination objects:\n\n- `page`\n- `isDone`\n- `continueCursor`\n\nRaw events are append-only source of truth. Rollups are serving layer.\n\n## Retention\n\nRetention is configured per site. Defaults are cost-conscious:\n\n- raw `events`: 90 days\n- hourly `rollups`: 90 days\n- daily `rollups`: kept indefinitely\n\n`retentionDays` is shared default for raw events and hourly rollups. Override\nspecific fields when needed:\n\n```ts\nregisterRoutes(http, components.convexAnalytics, {\n  path: \"/analytics/ingest\",\n  countryLookup: \"headers-only\",\n});\n```\n\n## Advanced: Cleanup and Retention\n\nCleanup is explicit so you control request volume and billing. For most apps,\nadd one cleanup action and one cron and stop thinking about it.\n\nIf you want custom schedules, this is the manual shape:\n\n```ts\n// convex/cleanup.ts\nimport { components } from \"./_generated/api\";\nimport { internalAction } from \"./_generated/server\";\nimport { v } from \"convex/values\";\n\nexport const site = internalAction({\n  args: {\n    slug: v.string(),\n    limit: v.optional(v.number()),\n  },\n  handler: async (ctx, args) => {\n    return await ctx.runAction(components.convexAnalytics.maintenance.cleanupSite, {\n      slug: args.slug,\n      limit: args.limit,\n    });\n  },\n});\n```\n\nThen schedule them:\n\n```ts\n// convex/crons.ts\nimport { cronJobs } from \"convex/server\";\nimport { internal } from \"./_generated/api\";\n\nconst crons = cronJobs();\n\ncrons.interval(\n  \"analytics cleanup\",\n  { hours: 6 },\n  internal.cleanup.site,\n  { slug: \"default\", limit: 100 },\n);\n\nexport default crons;\n```\n\nThese are admin functions. Do not call them from browser clients.\n\nUse `runUntilComplete: true` only for one-off backfills or after downtime. For\nnormal production cron, keep it unset and let each run delete a bounded batch.\n\n## React Native SDK\n\nInstall AsyncStorage alongside this package:\n\n```sh\nnpm install @react-native-async-storage/async-storage\n```\n\nThen use the React Native entry point:\n\n```ts\nimport { createRnAnalytics } from \"@abdssamie/convex-analytics/react-native\";\nimport AsyncStorage from \"@react-native-async-storage/async-storage\";\n\nconst analytics = await createRnAnalytics({\n  endpoint: \"https://your-deployment.convex.site/analytics/ingest\",\n  writeKey: process.env.ANALYTICS_WRITE_KEY!,\n  storage: AsyncStorage,\n});\n\nanalytics.track(\"screen_view\", { screen: \"Home\" });\nanalytics.identify(\"user_123\", { tier: \"pro\" });\n```\n\nThe React Native SDK uses the same ingestion engine as the browser SDK.\nThe only difference is the storage layer: instead of `localStorage`/`sessionStorage`,\nit uses `@react-native-async-storage/async-storage` (or any compatible storage provider).\n\n### Custom storage provider\n\nIf you prefer a different storage backend, pass any object that implements\n`getItem` and `setItem`:\n\n```ts\nconst analytics = await createRnAnalytics({\n  endpoint: \"...\",\n  writeKey: \"...\",\n  storage: {\n    getItem: (key: string) => Promise<string | null>,\n    setItem: (key: string, value: string) => Promise<void>,\n  },\n});\n```\n\n### Auto pageviews\n\nUnlike the browser SDK, the React Native SDK does not auto-track pageviews.\nCall `analytics.track(\"screen_view\", { screen: \"Home\" })` on navigation events:\n\n```ts\nimport { useNavigation } from \"@react-navigation/native\";\n\nfunction App() {\n  const navigation = useNavigation();\n\n  useEffect(() => {\n    const unsubscribe = navigation.addListener(\"state\", () => {\n      const route = navigation.getCurrentRoute();\n      if (route) {\n        analytics.track(\"screen_view\", { screen: route.name });\n      }\n    });\n    return unsubscribe;\n  }, [navigation]);\n}\n```\n\n## Browser SDK\n\nUse the browser helper in your frontend:\n\n```ts\nimport { createAnalytics } from \"@abdssamie/convex-analytics\";\n\nconst analytics = createAnalytics({\n  endpoint: \"https://your-deployment.convex.site/analytics/ingest\",\n  writeKey: \"write_...\",\n  autoPageviews: false,\n  flushIntervalMs: 5000,\n  maxBatchSize: 10,\n});\n\nanalytics.page();\nanalytics.track(\"signup_clicked\", { plan: \"pro\" });\nanalytics.identify(\"user_123\", { tier: \"pro\" });\nawait analytics.flush();\n```\n\nThe SDK stores:\n\n- `visitorId` in `localStorage`\n- `sessionId` in `sessionStorage`\n- queued events in memory only\n\nIt flushes on interval, batch size, and `pagehide`.\n\nFor React Native, see the [React Native SDK](#react-native-sdk) section below.\n\n`autoPageviews: true` works for traditional full-page loads. For SPAs, call\n`analytics.page()` on route changes yourself:\n\n```ts\nuseEffect(() => {\n  analytics.page();\n}, [analytics, pathname]);\n```\n\n## Cost Controls\n\nThe default ingest path is built to avoid unnecessary Convex usage:\n\n- Browser events are batched.\n- Raw events are slim.\n- Write keys are hashed before reaching component storage.\n- Ingest does not patch report counters inline.\n- Reports use hourly/daily rollups for common analytics queries.\n- Cleanup uses indexed, bounded batches and keeps daily rollups by default.\n- Event properties can be allowlisted or denied per site.\n- Raw IP addresses are not persisted by this component.\n\n## Note\n\nWhile this component has been optimized to reduce convex usage cost, if you \nhave many users or except to do so, then consider another service \nas convex-analytics hasn't been tested for large scale usage, but most \ndevelopers don't have to bother about this.\n\n## Publishing\n\nRelease scripts:\n\n- `npm run alpha`\n- `npm run release`\n- `npm run verify:release`\n\nBoth go through `preversion`, which runs:\n\n- `npm ci`\n- `npm run build:clean`\n- `npm run test`\n- `npm run lint`\n- `npm run typecheck`\n\n`npm run verify:release` adds `npm pack` on top, matching CI.\n\nThe package `version` script is non-interactive now. It just formats\n`CHANGELOG.md` and stages it if needed.\n\nGitHub Actions automation:\n\n- `CI` runs on every push to `main`, pull request, and manual dispatch.\n- `Publish` runs on `v*` tags and manual dispatch.\n- `Publish` requires an `NPM_TOKEN` repository secret.\n- Tag-based publish verifies that `vX.Y.Z` matches `package.json` version `X.Y.Z`.\n\n## Development\n\n```sh\nnpm install\nnpm run build:codegen\nnpm test\nnpm run typecheck\n```\n\nRun the example app:\n\n```sh\nnpm run dev\nnpm run dev:frontend\n```\n\nThe example frontend is a small product app that sends analytics events. It is\nnot a dashboard. Use the Convex dashboard to inspect component tables,\nfunctions, and stored events.\n","readmeFilename":"README.md"}