Analytics - v1.2.1
Hooks & Composables
Since 1.1.0
Shared logic for analytics data fetching and consent management, available as React hooks and Vue composables.
useAnalyticsApi
A generic data fetching hook/composable for the analytics API with support for polling, AbortController-based cleanup, and typed responses.
React
import { useAnalyticsApi } from '@/vendor/artisanpack-analytics/react';
import type { StatsData, AnalyticsQueryParams } from '@/vendor/artisanpack-analytics/react';
function StatsWidget() {
const { data, loading, error, refresh } = useAnalyticsApi<StatsData>({
endpoint: '/api/analytics/stats',
params: { period: '30d', site_id: 1 },
pollInterval: 30000, // Refresh every 30 seconds
fetchOnMount: true,
});
return (
<div>
{loading && <span>Loading...</span>}
{error && <span>Error: {error}</span>}
{data && <span>{data.pageviews} pageviews</span>}
<button onClick={refresh}>Refresh</button>
</div>
);
}
Vue
<script setup lang="ts">
import { useAnalyticsApi } from '@/vendor/artisanpack-analytics/vue';
import type { StatsData } from '@/vendor/artisanpack-analytics/vue';
const { data, loading, error, refresh } = useAnalyticsApi<StatsData>({
endpoint: '/api/analytics/stats',
params: { period: '30d', site_id: 1 },
pollInterval: 30000,
fetchOnMount: true,
});
</script>
Options
interface UseAnalyticsApiOptions<T> {
endpoint: string;
params?: AnalyticsQueryParams | RealtimeQueryParams;
pollInterval?: number;
initialData?: T;
fetchOnMount?: boolean;
}
| Option | Type | Default | Description |
|---|---|---|---|
endpoint |
string |
— | Required. API endpoint path (e.g., /api/analytics/stats) |
params |
AnalyticsQueryParams | RealtimeQueryParams |
{} |
Query parameters sent with each request |
pollInterval |
number |
— | Polling interval in milliseconds. Omit to disable polling. |
initialData |
T |
undefined |
Initial data before the first fetch completes |
fetchOnMount |
boolean |
true |
Whether to fetch immediately on mount |
Return Value
interface UseAnalyticsApiResult<T> {
data: T | undefined; // Fetched data (React: state, Vue: Ref<T>)
loading: boolean; // Whether a request is in progress
error: string | null; // Error message, or null
refresh: () => void; // Manually trigger a new fetch
}
Features
- AbortController: Requests are automatically cancelled on unmount or when a new request starts, preventing stale data from overwriting fresh data.
- Polling: Set
pollIntervalto automatically refetch data on a timer. Polling does not abort in-flight requests. - Reactive params: In Vue, changes to reactive
paramsautomatically trigger a new fetch. - Query string building: Params are automatically serialized as URL query parameters.
useConsent
A comprehensive consent management hook/composable that handles consent state, persistence, and server synchronization.
React
import { useConsent } from '@/vendor/artisanpack-analytics/react';
function ConsentManager() {
const {
loading,
error,
consentRequired,
categories,
hasConsent,
grantConsent,
revokeConsent,
acceptAll,
rejectAll,
updateConsent,
refresh,
} = useConsent({
apiPrefix: '/api/analytics',
fetchOnMount: true,
});
return (
<div>
<p>Analytics consent: {hasConsent('analytics') ? 'Granted' : 'Denied'}</p>
<button onClick={() => grantConsent('analytics')}>Grant Analytics</button>
<button onClick={() => revokeConsent('analytics')}>Revoke Analytics</button>
<button onClick={acceptAll}>Accept All</button>
<button onClick={rejectAll}>Reject All</button>
</div>
);
}
Vue
<script setup lang="ts">
import { useConsent } from '@/vendor/artisanpack-analytics/vue';
const {
loading,
error,
consentRequired,
categories,
hasConsent,
grantConsent,
revokeConsent,
acceptAll,
rejectAll,
updateConsent,
refresh,
} = useConsent({
apiPrefix: '/api/analytics',
fetchOnMount: true,
});
</script>
Options
interface UseConsentOptions {
apiPrefix?: string;
fetchOnMount?: boolean;
initialCategories?: Record<string, boolean>;
initialConsentRequired?: boolean;
}
| Option | Type | Default | Description |
|---|---|---|---|
apiPrefix |
string |
'' |
API endpoint prefix (e.g., /api/analytics) |
fetchOnMount |
boolean |
true |
Whether to fetch consent status on mount |
initialCategories |
Record<string, boolean> |
{} |
Initial consent category state |
initialConsentRequired |
boolean |
true |
Whether consent is required before tracking |
Return Value
| Property/Method | Type | Description |
|---|---|---|
loading |
boolean |
Whether a consent API request is in progress |
error |
string | null |
Error message, or null |
consentRequired |
boolean |
Whether consent is required by the config |
categories |
Record<string, boolean> |
Current consent state per category |
hasConsent(category) |
(category: string) => boolean |
Check if a specific category is granted |
grantConsent(category) |
(category: string) => Promise<void> |
Grant consent for a category |
revokeConsent(category) |
(category: string) => Promise<void> |
Revoke consent for a category |
acceptAll() |
() => Promise<void> |
Grant all categories |
rejectAll() |
() => Promise<void> |
Revoke all categories |
updateConsent(categories) |
(categories: Record<string, boolean>) => Promise<void> |
Bulk update consent |
refresh() |
() => Promise<void> |
Refetch consent status from server |
Persistence
Consent state is persisted in multiple locations for reliability:
- localStorage: Stores full consent state under the
artisanpack_consentkey - Cookies: Sets a
artisanpack_consentcookie (365-day expiry) for server-side access - Visitor ID: A unique visitor identifier is stored in both localStorage (
artisanpack_visitor_id) and a cookie for consent record association - Server: Consent is synced to the server via the consent API endpoints with CSRF token protection
Optimistic Updates
The hook uses optimistic updates for a responsive UI:
- Local state is updated immediately when the user makes a consent choice
- The change is sent to the server in the background
- If the server request fails, the local state is rolled back to the previous value
Security
- All consent API requests include a CSRF token from the
XSRF-TOKENcookie - The
Secureflag is set on cookies when the page is served over HTTPS - Concurrent update races are guarded against with request tracking