@ops-ai/toggly-appinsights-hook
v1.0.0
Published
Azure Application Insights hook for Toggly Feature Flags SDK. Automatically tracks feature flag data in Application Insights for monitoring and analytics.
Downloads
92
Readme
@ops-ai/toggly-appinsights-hook
Azure Application Insights hook for Toggly Feature Flags SDK. Automatically sends feature flag telemetry to Azure Application Insights for monitoring, analytics, and diagnostics correlation.
Can be used WITH or WITHOUT Toggly.io.
What is This?
This hook integrates Toggly feature flags with Azure Application Insights, allowing you to:
- Track feature flag evaluations as custom events
- Add feature flags as custom properties on all telemetry
- Correlate features with application behavior in Application Insights
- Set authenticated user context when identity changes
- Monitor real-time feature changes via custom events
- Analyze A/B test results using Application Insights analytics
- Create alerts based on feature flag state changes
How It Works
The AppInsightsHook implements the Toggly SDK Hook interface and listens to multiple lifecycle events:
| Hook | Application Insights Action |
|------|------------|
| afterEvaluation | Sends FeatureFlagEvaluated custom event via trackEvent() |
| afterIdentify | Sets authenticated user via setAuthenticatedUserContext() |
| afterRefresh | Sends FeatureFlagChanged event on state changes + updates telemetry properties |
Example event sent to Application Insights:
appInsights.trackEvent({
name: 'FeatureFlagEvaluated',
properties: {
feature_key: 'checkout-v2',
feature_enabled: 'true',
category: 'toggly'
}
});Installation
npm install @ops-ai/toggly-appinsights-hookOr with yarn:
yarn add @ops-ai/toggly-appinsights-hookPrerequisites
- Toggly SDK - Any JavaScript-based Toggly SDK with hooks support (v1.0.0+)
- Application Insights JavaScript SDK - Must be loaded on your page (
window.appInsights)
Setting up Application Insights
<!-- Add the Application Insights JavaScript SDK -->
<script type="text/javascript">
!(function (cfg){function e(){cfg.onInit&&cfg.onInit(i)}var S,u,D,t,n,i,C=window,x=document,w=C.location,I="script",b="ingestionendpoint",E="disableExceptionTracking",A="ai.device.";"instrumentationKey"[S="connectionString"];(D=cfg[S]||"")&&(D.indexOf("InstrumentationKey=")!==-1?u="IngestionEndpoint=https://dc.services.visualstudio.com/v2/track":u.indexOf("IngestionEndpoint=")!==-1||(u+=";IngestionEndpoint=https://dc.services.visualstudio.com/v2/track"));var l=D?D.replace("InstrumentationKey=",""):cfg.instrumentationKey||"",G=cfg.sdk||"javascript:snippet";G+=","+l;var v=["src","name","ld","useXhr","crossOrigin","onInit","cfg"];(function(cfg){for(var i=0;i<v.length;i++){var x=cfg[v[i]];x&&(D+=(D?";":"")+v[i]+"="+encodeURIComponent(x))}})(cfg);var c=C[t="appInsights"];c&&c.queue||(C[t]=i={config:cfg,initialize:!0,queue:[],sv:"8",version:2,snippet:G},cfg[E]||i.queue.push(["trackPageView",{}]),e())})(
{connectionString:"YOUR_CONNECTION_STRING"}
);
</script>
<script type="text/javascript" src="https://js.monitor.azure.com/scripts/b/ai.3.gbl.min.js" crossorigin="anonymous"></script>Usage
Vanilla JavaScript
import { Toggly } from '@ops-ai/feature-flags-toggly';
import { AppInsightsHook } from '@ops-ai/toggly-appinsights-hook';
Toggly.init({
appKey: 'your-app-key',
environment: 'Production',
hooks: [
new AppInsightsHook({
trackEvaluations: true,
trackChanges: true,
setCustomProperties: true,
checkConsent: () => cookieConsent.analytics
})
]
});React
import { createTogglyProvider } from '@ops-ai/react-feature-flags-toggly';
import { AppInsightsHook } from '@ops-ai/toggly-appinsights-hook';
const TogglyProvider = await createTogglyProvider({
appKey: 'your-app-key',
environment: 'Production',
hooks: [new AppInsightsHook({ setCustomProperties: true })]
});Angular
import { provideToggly } from '@ops-ai/ngx-feature-flags-toggly';
import { AppInsightsHook } from '@ops-ai/toggly-appinsights-hook';
bootstrapApplication(AppComponent, {
providers: [
provideToggly({
appKey: 'your-app-key',
environment: 'Production',
hooks: [new AppInsightsHook({ setCustomProperties: true })]
})
]
});Vue
import { createApp } from 'vue';
import { TogglyPlugin } from 'vue-feature-flags-toggly';
import { AppInsightsHook } from '@ops-ai/toggly-appinsights-hook';
app.use(TogglyPlugin, {
appKey: 'your-app-key',
environment: 'Production',
hooks: [new AppInsightsHook({ setCustomProperties: true })]
});Svelte
import { Toggly } from '@ops-ai/feature-flags-toggly';
import { AppInsightsHook } from '@ops-ai/toggly-appinsights-hook';
Toggly.init({
appKey: 'your-app-key',
environment: 'Production',
hooks: [new AppInsightsHook({ setCustomProperties: true })]
});Astro
import { Toggly } from '@ops-ai/feature-flags-toggly';
import { AppInsightsHook } from '@ops-ai/toggly-appinsights-hook';
Toggly.init({
appKey: 'your-app-key',
environment: 'Production',
hooks: [new AppInsightsHook({ setCustomProperties: true })]
});Configuration
interface AppInsightsHookOptions {
// Enable or disable the hook (default: true)
enabled?: boolean;
// Application Insights instrumentation key (optional, uses window.appInsights)
instrumentationKey?: string;
// Event name for evaluations (default: "FeatureFlagEvaluated")
evaluationEventName?: string;
// Event name for changes (default: "FeatureFlagChanged")
changeEventName?: string;
// Track feature evaluations (default: true)
trackEvaluations?: boolean;
// Track both true and false results (default: true)
trackAllResults?: boolean;
// Set custom properties on all telemetry (default: true)
setCustomProperties?: boolean;
// Property name prefix (default: "ff_")
propertyPrefix?: string;
// Track real-time changes (default: true)
trackChanges?: boolean;
// Track user identity (default: true)
trackIdentity?: boolean;
// Custom properties for all events
customProperties?: Record<string, string | number | boolean>;
// Custom measurements for all events
customMeasurements?: Record<string, number>;
// Consent callback (default: () => true)
checkConsent?: () => boolean;
// Debug mode (default: false)
debug?: boolean;
}| Option | Type | Default | Description |
|--------|------|---------|-------------|
| enabled | boolean | true | Enable or disable the hook entirely |
| instrumentationKey | string | - | Instrumentation key (optional, uses global appInsights) |
| evaluationEventName | string | "FeatureFlagEvaluated" | Custom event name for evaluations |
| changeEventName | string | "FeatureFlagChanged" | Custom event name for changes |
| trackEvaluations | boolean | true | Track feature flag evaluations |
| trackAllResults | boolean | true | Track both true and false results |
| setCustomProperties | boolean | true | Add feature flags as custom properties on all telemetry |
| propertyPrefix | string | "ff_" | Prefix for property names |
| trackChanges | boolean | true | Track real-time feature changes |
| trackIdentity | boolean | true | Set authenticated user context |
| customProperties | object | {} | Custom properties for all events |
| customMeasurements | object | {} | Custom measurements for all events |
| checkConsent | function | () => true | Consent check callback |
| debug | boolean | false | Enable debug logging |
Full Configuration Example
const appInsightsHook = new AppInsightsHook({
enabled: process.env.NODE_ENV === 'production',
evaluationEventName: 'FF_Evaluated',
changeEventName: 'FF_Changed',
trackEvaluations: true,
trackAllResults: true,
setCustomProperties: true,
propertyPrefix: 'feature_',
trackChanges: true,
trackIdentity: true,
customProperties: {
app_version: '2.0.0',
environment: 'production'
},
customMeasurements: {
session_duration: 120
},
checkConsent: () => {
return window.cookieConsent?.analytics ?? false;
},
debug: false
});What Gets Tracked
Feature Evaluations
When a feature flag is evaluated:
appInsights.trackEvent({
name: 'FeatureFlagEvaluated',
properties: {
feature_key: 'new-checkout-flow',
feature_enabled: 'true',
category: 'toggly'
}
});Feature Changes (Real-time)
When a feature flag state changes:
appInsights.trackEvent({
name: 'FeatureFlagChanged',
properties: {
feature_key: 'dark-mode',
old_value: 'false',
new_value: 'true',
category: 'toggly'
}
});Custom Properties on All Telemetry
When setCustomProperties: true, feature flags are added as custom properties to all telemetry:
// All telemetry (page views, exceptions, requests, etc.) will include:
{
ff_dark_mode: 'enabled',
ff_new_checkout: 'disabled'
}This is achieved via Application Insights' addTelemetryInitializer API.
User Identity
When identity is set:
appInsights.setAuthenticatedUserContext('[email protected]');Viewing Data in Azure Portal
Custom Events
- Go to Azure Portal → Application Insights resource
- Navigate to Logs (Analytics)
- Query custom events:
customEvents
| where name == "FeatureFlagEvaluated"
| extend feature_key = tostring(customDimensions.feature_key)
| extend feature_enabled = tostring(customDimensions.feature_enabled)
| summarize count() by feature_key, feature_enabled
| order by count_ descFeature Flag Correlation
Correlate feature flags with other telemetry:
// Find exceptions by feature flag
exceptions
| extend dark_mode = tostring(customDimensions.ff_dark_mode)
| summarize count() by dark_mode, type// Performance by feature flag
requests
| extend checkout_v2 = tostring(customDimensions.ff_checkout_v2)
| summarize avg(duration), percentile(duration, 95) by checkout_v2Creating Alerts
Create alerts when feature flags change:
- Go to Alerts → Create alert rule
- Select Custom log search
- Query:
customEvents | where name == "FeatureFlagChanged" | where customDimensions.feature_key == "critical-feature"
Privacy & Consent
GDPR/CCPA Compliance
The checkConsent callback allows integration with consent management platforms:
// OneTrust example
new AppInsightsHook({
checkConsent: () => window.OneTrust?.IsAlertBoxClosed() &&
window.OneTrust?.GetDomainData()?.Groups
?.find(g => g.CustomGroupId === 'C0002')?.Status === 'active'
});
// Simple cookie consent example
new AppInsightsHook({
checkConsent: () => document.cookie.includes('analytics_consent=true')
});What data is sent
- Feature flag key name (e.g.,
"dark-mode") - Feature evaluation result (
true/false) - Custom properties you explicitly configure
- User ID (only if
trackIdentityis enabled and identity is set) - No automatic PII collection
Error Handling
The hook is designed to never break the Toggly SDK:
- All Application Insights API calls are wrapped in try-catch
- If appInsights is not loaded, events are silently skipped
- If appInsights throws an error, it is caught and logged to console
- The hook provides a console warning (not error) if appInsights is not detected at initialization
Performance
- Overhead: <0.1ms per evaluation
- Bundle Size: ~2KB (minified)
- No batching: Events use Application Insights' internal batching
- Short-circuit: Disabled hooks and filtered results exit immediately
- Telemetry Initializer: Registered once, runs efficiently on each telemetry item
Dynamic Hook Management
You can add or remove the hook at runtime:
import { Toggly } from '@ops-ai/feature-flags-toggly';
import { AppInsightsHook } from '@ops-ai/toggly-appinsights-hook';
// Add hook after initialization
Toggly.addHook(new AppInsightsHook({ setCustomProperties: true }));
// Remove hook by name
Toggly.removeHook('appinsights-hook');Troubleshooting
Events not appearing in Application Insights
Check appInsights is loaded: Ensure the Application Insights SDK is on the page before Toggly initializes
console.log('appInsights available:', typeof window.appInsights !== 'undefined');Check connection string: Verify your Application Insights connection string is correct
Check consent: Verify your
checkConsentcallback returnstrueCheck feature evaluation: Ensure your feature flags are actually being evaluated
Check the console: Look for
[Toggly AppInsights Hook]messagesEnable debug mode:
new AppInsightsHook({ debug: true })Check Azure Portal delay: Application Insights data may take a few minutes to appear
Console warning at startup
[Toggly AppInsights Hook] Application Insights SDK not detected.This means appInsights was not loaded when the hook was created. The hook will automatically start sending events once appInsights becomes available.
Custom properties not appearing
- Property names are sanitized: special characters replaced with underscores
- Property names are truncated to 150 characters (Application Insights limit)
- Ensure
setCustomPropertiesis set totrue
Development
Running Tests
npm testRunning Tests with Coverage
npm test -- --coverageBuilding
npm run buildType Checking
npm run typecheckTypeScript Support
Full TypeScript support included:
import { AppInsightsHook } from '@ops-ai/toggly-appinsights-hook';
import type { AppInsightsHookOptions } from '@ops-ai/toggly-appinsights-hook';
const options: AppInsightsHookOptions = {
enabled: true,
trackEvaluations: true,
setCustomProperties: true,
};
const hook = new AppInsightsHook(options);Requirements
- Toggly SDK: Any JS SDK v1.0.0+ with hooks support
- Application Insights: JavaScript SDK loaded on the page
- Browser: Modern browsers with ES2020+ support
- Node.js: 18+ (for development)
Related Packages
- @ops-ai/toggly-hooks-types - Hook type definitions
- @ops-ai/toggly-ga4-hook - Google Analytics 4 hook
- @ops-ai/toggly-clarity-hook - Microsoft Clarity hook
- @ops-ai/feature-flags-toggly - Core JavaScript SDK
- @ops-ai/react-feature-flags-toggly - React SDK
- @ops-ai/ngx-feature-flags-toggly - Angular SDK
Find Out More
- Toggly Documentation
- Application Insights JavaScript SDK
- Application Insights Documentation
- Toggly Hooks Guide
License
MIT
