Welcome to the final chapter of the Analytics project!
In the previous chapter, Datadog Integration, we built a real-time dashboard that acts like a "Check Engine" light. It tells us immediately if something is wrong.
But here is the scary part: Imagine you see that light turn red. A new feature is crashing the application for 50% of your users.
If you have to write a code fix, review it, build a new version, and ask thousands of users to download the update... that might take days. By then, the users are gone.
We need a way to turn that broken feature off instantly, without deploying new code.
Enter Dynamic Configuration (powered by GrowthBook). This is the "Remote Control" for our application.
Usually, developers write code like this:
const IS_NEW_UI_ENABLED = true; // โ Hardcoded!
if (IS_NEW_UI_ENABLED) {
showNewInterface();
}
To change this to false, you have to change the source code and release a new version of the software.
With Dynamic Configuration, we write this:
// โ
Dynamic! Ask the system what to do.
const isEnabled = getFeatureValue('new_ui_enabled');
if (isEnabled) {
showNewInterface();
}
Now, we can log into the GrowthBook website, flip a switch, and within minutes, isEnabled becomes false on every user's machine around the world.
The most common use case is a boolean (true/false) flag.
upload_file command because the server is down."Sometimes we need more than just On/Off. We need to tune numbers or text.
Fetching configuration from a server takes time (network latency). We cannot block the application startup while we wait for the internet.
To solve this, we use a stale-while-revalidate strategy, which is like reading the morning newspaper.
Let's look at growthbook.ts. This file wraps the official GrowthBook SDK to handle our specific caching needs.
Before we ask for config, we need to tell GrowthBook who is asking. This allows us to say "Turn this feature on for Windows users only."
We use the data we learned about in Metadata & Context Enrichment.
// growthbook.ts
function getUserAttributes(): GrowthBookUserAttributes {
// Get the standard user profile
const user = getUserForGrowthBook()
return {
id: user.deviceId,
platform: user.platform, // 'win32', 'darwin'
appVersion: user.appVersion,
// ... other attributes
}
}
This is the most important function in the entire file. getFeatureValue_CACHED_MAY_BE_STALE allows us to check a flag synchronously (instantly) without using await.
It looks at the file we saved on the hard drive during the previous run.
// growthbook.ts
export function getFeatureValue_CACHED_MAY_BE_STALE<T>(
feature: string,
defaultValue: T,
): T {
// 1. Check if we have this feature in our disk cache
const config = getGlobalConfig() // Reads ~/.claude.json
const cached = config.cachedGrowthBookFeatures?.[feature]
// 2. If found, return it immediately!
if (cached !== undefined) {
return cached as T
}
// 3. If not found, use the default (safe fallback)
return defaultValue
}
Note: The name MAY_BE_STALE reminds developers that this value might be a few hours old, which is usually fine for UI features.
While the app is running, we connect to GrowthBook to get updates. This happens in initializeGrowthBook.
// growthbook.ts
// Create the client with our user attributes
const gb = new GrowthBook({
apiHost: 'https://api.anthropic.com/',
clientKey: getGrowthBookClientKey(),
attributes: getUserAttributes(),
})
// Fetch from network
gb.init({ timeout: 5000 }).then(async () => {
// When network returns, save the new values to disk!
syncRemoteEvalToDisk()
})
When the new data arrives, we save it so it's ready for the next time the user opens the app.
// growthbook.ts
function syncRemoteEvalToDisk(): void {
// Get all the new values the server sent us
const fresh = Object.fromEntries(remoteEvalFeatureValues)
// Save to our global config file
saveGlobalConfig(current => ({
...current,
cachedGrowthBookFeatures: fresh,
}))
}
You might notice a setting remoteEval: true in the code.
Standard feature flags download rules to the client (e.g., "If version > 2.0, return true"). The client does the math.
Remote Evaluation means we send the user's attributes to the server, the server does the math, and sends back only the final result (true).
Why do we use this?
We have now built a complete telemetry and control system.
The Dynamic Configuration module is the final piece of the puzzle. It closes the feedback loop.
You now understand the full lifecycle of data within the analytics project. You know how to log events safely, how they are transported, and how we control the system remotely.
End of Tutorial.
Generated by Code IQ