Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/FUNDING.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
github: [thyngster]
53 changes: 53 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
name: CI

on:
push:
branches:
- main

pull_request:
branches:
- main

jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
run_install: false
- uses: actions/setup-node@v4
with:
node-version: lts/*
cache: pnpm

- run: pnpm i -g @antfu/ni
- run: nci
- run: nr lint
- run: nr typecheck

test:
runs-on: ${{ matrix.os }}

strategy:
matrix:
node: [lts/*]
os: [ubuntu-latest, windows-latest, macos-latest]
fail-fast: false

steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
run_install: false
- name: Set node ${{ matrix.node }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node }}
cache: pnpm

- run: pnpm i -g @antfu/ni
- run: nci
- run: nr build
- run: nr test
35 changes: 35 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
name: Release

permissions:
id-token: write
contents: write

on:
push:
tags:
- 'v*'

jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
with:
node-version: lts/*
registry-url: https://registry.npmjs.org/

- run: pnpm dlx changelogithub
env:
GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}

# # Uncomment the following lines to publish to npm on CI
#
# - run: pnpm install
# - run: pnpm publish --no-git-checks -r --access public
# env:
# NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}
# NPM_CONFIG_PROVENANCE: true
12 changes: 12 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
.cache
.DS_Store
.idea
*.log
*.tgz
coverage
dist
lib-cov
logs
node_modules
temp
playground
2 changes: 2 additions & 0 deletions .npmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
ignore-workspace-root-check=true
shell-emulator=true
6 changes: 6 additions & 0 deletions .vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"recommendations": [
"dbaeumer.vscode-eslint",
"antfu.pnpm-catalog-lens"
]
}
38 changes: 38 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
// Disable the default formatter, use eslint instead
"prettier.enable": false,
"editor.formatOnSave": false,

// Auto fix
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit",
"source.organizeImports": "never"
},

// Silent the stylistic rules in you IDE, but still auto fix them
"eslint.rules.customizations": [
{ "rule": "style/*", "severity": "off" },
{ "rule": "*-indent", "severity": "off" },
{ "rule": "*-spacing", "severity": "off" },
{ "rule": "*-spaces", "severity": "off" },
{ "rule": "*-order", "severity": "off" },
{ "rule": "*-dangle", "severity": "off" },
{ "rule": "*-newline", "severity": "off" },
{ "rule": "*quotes", "severity": "off" },
{ "rule": "*semi", "severity": "off" }
],

// Enable eslint for all supported languages
"eslint.validate": [
"javascript",
"javascriptreact",
"typescript",
"typescriptreact",
"vue",
"html",
"markdown",
"json",
"jsonc",
"yaml"
]
}
1 change: 1 addition & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Please refer to https://github.com/antfu/contribute
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2025 Analytics Debugger S.L.U.
Copyright (c) 2025 Analytics Debugger S.L.U. David Vallejo <https://github.com/thyngster>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
202 changes: 201 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,201 @@
# ads-click-tracker
# 🎯 Ads Click Tracker

[![npm version](https://img.shields.io/npm/v/ads-click-tracker)](https://www.npmjs.com/package/ads-click-tracker)
[![bundle size](https://img.shields.io/bundlephobia/minzip/ads-click-tracker)](https://bundlephobia.com/package/ads-click-tracker)
[![license](https://img.shields.io/npm/l/ads-click-tracker)](LICENSE)
[![Downloads](https://img.shields.io/npm/dm/ads-click-tracker)](https://www.npmjs.com/package/ads-click-tracker)

## 📖 Overview

Ads Click Tracker is a powerful, lightweight solution for marketing attribution tracking that simplifies the complexity of capturing and managing click data across multiple advertising platforms.

## 🌟 Key Features

- **💡 Comprehensive Attribution Tracking**
- Automatically capture click IDs from various sources
- Track landing pages and referrer URLs with precision
- Store and manage marketing touchpoints effortlessly

- **⏰ Flexible Expiration Management**
- Set custom expiration times for different click sources
- Automatic cleanup of stale click data
- Configurable click limits per source

- **🔍 Intelligent URL Parsing**
- Detect parameters in both URL and hash fragments
- Support for multiple click ID formats (Google, Facebook, custom UTM)

- **💾 Efficient Storage Handling**
- Lightweight localStorage persistence
- Automatic data management and cleanup
- Minimal performance overhead

- **🚀 Developer-Friendly**
- Zero dependencies
- Full TypeScript support
- < 912 bytes gzipped
- Simple, intuitive API

## 🔧 Installation

```bash
# npm
npm install ads-click-tracker

# Yarn
yarn add ads-click-tracker

# pnpm
pnpm add ads-click-tracker
```

## 💻 Quick Start

### Basic Usage

```javascript
import { initTracker } from 'ads-click-tracker'

// Initialize with multiple click ID configurations
const tracker = initTracker({
clickIdConfigs: [
{ name: 'gclid', expirationMs: 30 * 24 * 60 * 60 * 1000 }, // 30 days for Google Ads
{ name: 'fbclid', maxClicks: 50 } // 50 clicks limit for Facebook
],
debug: true // Enable console logging
})

// Manually track a click
tracker.trackClick('affiliate', 'ref123', 24 * 60 * 60 * 1000) // 1 day expiration

// Retrieve tracked clicks
const googleClicks = tracker.getClicks('gclid')
```

## 📊 Click Data Structure

Each tracked click includes:

```typescript
interface TrackedClick {
value: string // Click ID (e.g., "abc123")
timestamp: number // Recording timestamp (milliseconds)
expiresAt: number // Expiration timestamp (milliseconds)
landing: string // Landing page URL
referrer: string // Referring URL
}
```

## ⚙️ Configuration Options

### `initTracker(options)`

| Option | Type | Description | Default |
|--------|------|-------------|---------|
| `storageKey` | `string` | Custom storage key in localStorage | `'_ads_clicks'` |
| `clickIdConfigs` | `ClickConfig[]` | Click ID tracking configurations | `[]` |
| `debug` | `boolean` | Enable debug logging | `false` |

### `ClickConfig`

| Property | Type | Description |
|----------|------|-------------|
| `name` | `string` | Parameter name (e.g., 'gclid') |
| `expirationMs` | `number?` | Expiration time in milliseconds |
| `maxClicks` | `number?` | Maximum number of clicks to store |

## 📚 API Reference

### `trackClick(source, value, expirationMs?)`

Manually track a click:

```javascript
tracker.trackClick(
'campaign_id', // Source name
'summer_sale', // Click ID value
7 * 24 * 60 * 60 * 1000 // Optional 7-day expiration
)
```

### `getClicks(source?)`

Retrieve tracked clicks:

```javascript
// Get all active clicks
const allClicks = tracker.getClicks()

// Get clicks for a specific source
const fbClicks = tracker.getClicks('fbclid')
```

### `clear(source?)`

Clear stored clicks:

```javascript
// Clear Google clicks
tracker.clear('gclid')

// Clear all clicks
tracker.clear()
```

## 🚀 Advanced Examples

### Marketing Attribution Setup

```javascript
const marketingTracker = initTracker({
storageKey: 'marketing_clicks',
clickIdConfigs: [
{ name: 'gclid', expirationMs: 30 * 24 * 60 * 60 * 1000 }, // Google (30 days)
{ name: 'fbclid', expirationMs: 7 * 24 * 60 * 60 * 1000 }, // Facebook (7 days)
{ name: 'utm_campaign', maxClicks: 200 } // Custom campaign tracking
]
})
```

### React Integration

```javascript
import { initTracker } from 'ads-click-tracker'
import { useEffect } from 'react'

function useClickTracker() {
useEffect(() => {
const tracker = initTracker({
clickIdConfigs: [{ name: 'campaign_id' }]
})

return () => tracker.clear()
}, [])
}
```

## 🌐 Browser Support

- Chrome
- Firefox
- Safari
- Edge (latest versions)

**Requirements:**
- localStorage support
- Modern browsers

**Note:** Internet Explorer 11 is not supported

## 📜 License

MIT License

## 🤝 Contributing

Contributions, issues, and feature requests are welcome!
Feel free to check [issues page](https://github.com/yourusername/ads-click-tracker/issues).

## 🌟 Show Your Support

Give a ⭐️ if this project helped you!
Loading
Loading