SDK version tracking
Track which SDK versions are deployed across your projects and environments to maintain security, compatibility, and access to the latest features.
Why track SDK versions
Tracking SDK versions helps you:
- Identify outdated SDKs that may have security vulnerabilities
- Understand which SDKs are approaching end-of-life
- Plan SDK upgrade initiatives across your organization
- Monitor relay proxy versions alongside client SDKs
- Maintain compliance with security policies
SDK versions API endpoint
LaunchDarkly provides a dedicated API endpoint to retrieve detailed SDK version usage data. The endpoint returns one record per unique SDK and project/environment combination, representing the maximum version observed in the last day.
Endpoint details
Endpoint:
GET https://app.launchdarkly.com/api/v2/usage/sdk-versions/details
Authentication: The endpoint requires an API access token with appropriate permissions. Include the token in the Authorization header.
Beta API header:
This endpoint is currently in beta. Include the LD-API-Version: beta header in your requests:
curl -H "Authorization: api-your-access-token" \
-H "LD-API-Version: beta" \
https://app.launchdarkly.com/api/v2/usage/sdk-versions/details
Data refresh: The endpoint refreshes hourly and returns the maximum version for each SDK observed in the last day.
Response data
The endpoint returns an array of SDK version records. Each record includes:
| Field | Description |
|---|---|
name | SDK name |
version | Observed SDK version |
type | SDK type |
projectId | Project identifier |
projectKey | Project key |
projectName | Project display name |
environmentId | Environment identifier |
environmentKey | Environment key |
environmentName | Environment display name |
applicationId | Application identifier if available |
ldLatestVersion | Latest available minor version from LaunchDarkly (truncated semver, e.g. 9.11). May be empty if the SDK type is unrecognized. The installed version may legitimately exceed this value while still showing EolAllClear. |
eolStatus | End-of-life status. Possible values: EolAllClear (supported), EolUnknown (SDK type not recognized), EolPast (past end-of-life), MajorVersionAvailable (new major version available, upgrade recommended) |
latestReleaseUrl | URL to latest SDK release |
connectionType | Connection type. Possible values: direct, relay |
relayVersion | Relay proxy version if connected through relay |
relayEolStatus | Relay proxy end-of-life status |
relayLatestVersion | Latest available relay proxy version |
relayLatestReleaseUrl | URL to latest relay proxy release |
Example requests
Python:
import requests
url = "https://app.launchdarkly.com/api/v2/usage/sdk-versions/details"
headers = {
"Authorization": "api-your-access-token",
"LD-API-Version": "beta"
}
response = requests.get(url, headers=headers)
sdk_versions = response.json()
for sdk in sdk_versions:
print(f"{sdk['name']} v{sdk['version']} in {sdk['projectKey']}/{sdk['environmentKey']}")
if sdk.get('eolStatus'):
print(f" EOL Status: {sdk['eolStatus']}")
JavaScript:
const url = 'https://app.launchdarkly.com/api/v2/usage/sdk-versions/details';
const options = {
method: 'GET',
headers: {
'Authorization': 'api-your-access-token',
'LD-API-Version': 'beta'
}
};
async function main() {
const response = await fetch(url, options);
const sdkVersions = await response.json();
sdkVersions.forEach(sdk => {
console.log(`${sdk.name} v${sdk.version} in ${sdk.projectKey}/${sdk.environmentKey}`);
if (sdk.eolStatus) {
console.log(` EOL Status: ${sdk.eolStatus}`);
}
});
}
main().catch(console.error);
Go:
package main
import (
"encoding/json"
"fmt"
"net/http"
"io"
)
type SDKVersion struct {
Name string `json:"name"`
Version string `json:"version"`
ProjectKey string `json:"projectKey"`
EnvironmentKey string `json:"environmentKey"`
EOLStatus string `json:"eolStatus"`
LatestVersion string `json:"ldLatestVersion"`
}
func main() {
url := "https://app.launchdarkly.com/api/v2/usage/sdk-versions/details"
req, err := http.NewRequest("GET", url, nil)
if err != nil {
fmt.Printf("error creating request: %v\n", err)
return
}
req.Header.Add("Authorization", "api-your-access-token")
req.Header.Add("LD-API-Version", "beta")
res, err := http.DefaultClient.Do(req)
if err != nil {
fmt.Printf("error making request: %v\n", err)
return
}
defer res.Body.Close()
if res.StatusCode != http.StatusOK {
fmt.Printf("unexpected status: %d\n", res.StatusCode)
return
}
body, err := io.ReadAll(res.Body)
if err != nil {
fmt.Printf("error reading response: %v\n", err)
return
}
var versions []SDKVersion
if err := json.Unmarshal(body, &versions); err != nil {
fmt.Printf("error parsing response: %v\n", err)
return
}
for _, sdk := range versions {
fmt.Printf("%s v%s in %s/%s\n", sdk.Name, sdk.Version, sdk.ProjectKey, sdk.EnvironmentKey)
if sdk.EOLStatus != "" {
fmt.Printf(" EOL Status: %s\n", sdk.EOLStatus)
}
}
}
Use cases
Identify outdated SDKs
Query the API to find SDKs running behind the latest available version. Because ldLatestVersion uses truncated semver (for example 9.11 rather than 9.11.0), a simple string comparison is unreliable — use a tuple comparison to avoid false positives when the installed version is a newer patch:
import requests
url = "https://app.launchdarkly.com/api/v2/usage/sdk-versions/details"
headers = {
"Authorization": "api-your-access-token",
"LD-API-Version": "beta"
}
def parse_version(v):
try:
return tuple(int(x) for x in v.split('.'))
except (ValueError, AttributeError):
return (0,)
response = requests.get(url, headers=headers)
sdk_versions = response.json()
outdated_sdks = [
sdk for sdk in sdk_versions
if sdk.get('ldLatestVersion')
and parse_version(sdk.get('version', '')) < parse_version(sdk['ldLatestVersion'])
]
print(f"Found {len(outdated_sdks)} outdated SDK instances")
for sdk in outdated_sdks:
print(f" {sdk['name']} v{sdk['version']} in {sdk['projectKey']}/{sdk['environmentKey']}")
print(f" Latest: v{sdk['ldLatestVersion']}")
print(f" Release: {sdk['latestReleaseUrl']}")
Monitor end-of-life SDKs
Identify SDKs approaching or past their end-of-life:
import requests
url = "https://app.launchdarkly.com/api/v2/usage/sdk-versions/details"
headers = {
"Authorization": "api-your-access-token",
"LD-API-Version": "beta"
}
response = requests.get(url, headers=headers)
sdk_versions = response.json()
EOL_CLEAR = {'EolAllClear', 'EolUnknown', ''}
eol_sdks = [
sdk for sdk in sdk_versions
if sdk.get('eolStatus') and sdk['eolStatus'] not in EOL_CLEAR
]
print(f"Found {len(eol_sdks)} SDKs with EOL concerns")
for sdk in eol_sdks:
print(f" {sdk['name']} v{sdk['version']} in {sdk['projectKey']}/{sdk['environmentKey']}")
print(f" Status: {sdk['eolStatus']}")
Track relay proxy versions
Monitor relay proxy versions across your infrastructure:
import requests
url = "https://app.launchdarkly.com/api/v2/usage/sdk-versions/details"
headers = {
"Authorization": "api-your-access-token",
"LD-API-Version": "beta"
}
response = requests.get(url, headers=headers)
sdk_versions = response.json()
relay_connections = [
sdk for sdk in sdk_versions
if sdk.get('relayVersion')
]
print(f"Found {len(relay_connections)} SDKs connected through relay proxy")
for sdk in relay_connections:
print(f" {sdk['name']} v{sdk['version']} in {sdk['projectKey']}/{sdk['environmentKey']}")
print(f" Relay: v{sdk['relayVersion']}")
if sdk.get('relayEolStatus'):
print(f" Relay EOL Status: {sdk['relayEolStatus']}")
Generate upgrade reports
Create comprehensive reports for SDK upgrade planning:
import requests
from collections import defaultdict
url = "https://app.launchdarkly.com/api/v2/usage/sdk-versions/details"
headers = {
"Authorization": "api-your-access-token",
"LD-API-Version": "beta"
}
response = requests.get(url, headers=headers)
sdk_versions = response.json()
# Group by SDK name
sdks_by_name = defaultdict(list)
for sdk in sdk_versions:
sdks_by_name[sdk['name']].append(sdk)
# Generate report
print("SDK Upgrade Report")
print("=" * 80)
for sdk_name, instances in sdks_by_name.items():
versions = set(inst['version'] for inst in instances)
latest = instances[0].get('ldLatestVersion', 'Unknown')
print(f"\n{sdk_name}")
print(f" Versions in use: {', '.join(sorted(versions))}")
print(f" Latest available: {latest}")
print(f" Total instances: {len(instances)}")
# Count by environment
envs = defaultdict(int)
for inst in instances:
envs[f"{inst['projectKey']}/{inst['environmentKey']}"] += 1
print(f" Deployments:")
for env, count in sorted(envs.items()):
print(f" {env}: {count}")
Automation
Scheduled monitoring with PagerDuty notifications
Set up scheduled jobs to monitor SDK versions and create PagerDuty events. This example creates one event per SDK type that needs attention:
import requests
from collections import defaultdict
def check_sdk_versions():
"""Check SDK versions and create PagerDuty events for outdated SDKs"""
url = "https://app.launchdarkly.com/api/v2/usage/sdk-versions/details"
headers = {
"Authorization": "api-your-access-token",
"LD-API-Version": "beta"
}
response = requests.get(url, headers=headers)
sdk_versions = response.json()
# Group issues by SDK type
issues_by_sdk = defaultdict(list)
for sdk in sdk_versions:
sdk_name = sdk['name']
# Check for EOL status
if sdk.get('eolStatus') and sdk['eolStatus'] not in ['EolAllClear', 'EolUnknown']:
issues_by_sdk[sdk_name].append({
'type': 'eol',
'version': sdk['version'],
'project': sdk['projectKey'],
'environment': sdk['environmentKey'],
'status': sdk['eolStatus']
})
# Check for outdated versions
elif sdk.get('ldLatestVersion') and sdk.get('version') != sdk.get('ldLatestVersion'):
issues_by_sdk[sdk_name].append({
'type': 'outdated',
'version': sdk['version'],
'latest': sdk['ldLatestVersion'],
'project': sdk['projectKey'],
'environment': sdk['environmentKey']
})
# Create one PagerDuty event per SDK type with issues
for sdk_name, issues in issues_by_sdk.items():
create_pagerduty_event(sdk_name, issues)
def create_pagerduty_event(sdk_name, issues):
"""Create a PagerDuty Events API v2 event for a specific SDK type"""
# Determine severity based on issue types
has_eol = any(issue['type'] == 'eol' for issue in issues)
severity = 'error' if has_eol else 'warning'
# Build summary and details
summary = f"{sdk_name}: {len(issues)} instance(s) need updating"
# Group issues by type
eol_issues = [i for i in issues if i['type'] == 'eol']
outdated_issues = [i for i in issues if i['type'] == 'outdated']
details = {
'sdk_name': sdk_name,
'total_issues': len(issues),
'eol_count': len(eol_issues),
'outdated_count': len(outdated_issues),
'issues': issues
}
# Build custom details for better context
custom_details = {}
if eol_issues:
custom_details['eol_instances'] = [
f"{i['project']}/{i['environment']}: v{i['version']} ({i['status']})"
for i in eol_issues[:5] # Limit to first 5
]
if outdated_issues:
custom_details['outdated_instances'] = [
f"{i['project']}/{i['environment']}: v{i['version']} (latest: v{i['latest']})"
for i in outdated_issues[:5] # Limit to first 5
]
# PagerDuty Events API v2 payload
payload = {
'routing_key': 'your-integration-key-here',
'event_action': 'trigger',
'dedup_key': f'launchdarkly-sdk-{sdk_name.lower().replace(" ", "-")}',
'payload': {
'summary': summary,
'severity': severity,
'source': 'LaunchDarkly SDK Version Monitor',
'custom_details': custom_details
},
'links': [
{
'href': 'https://app.launchdarkly.com',
'text': 'LaunchDarkly Dashboard'
}
]
}
# Send to PagerDuty Events API v2
pagerduty_url = 'https://events.pagerduty.com/v2/enqueue'
response = requests.post(pagerduty_url, json=payload)
if response.status_code == 202:
print(f"✓ PagerDuty event created for {sdk_name}")
else:
print(f"✗ Failed to create PagerDuty event for {sdk_name}: {response.text}")
# Run this script on a schedule using cron or similar
check_sdk_versions()
Example PagerDuty events created:
When this script runs against an account with outdated SDKs, it creates separate events:
-
Python Server SDK event:
- Summary: “Python Server SDK: 3 instance(s) need updating”
- Severity: warning
- Custom details showing which projects/environments need updates
-
React SDK event:
- Summary: “React SDK: 5 instance(s) need updating”
- Severity: warning
- Lists outdated instances
-
.NET Server SDK event:
- Summary: “.NET Server SDK: 1 instance(s) need updating”
- Severity: error (if EOL)
- Shows EOL status and affected deployments
Key features:
- Deduplication: Uses
dedup_keyper SDK type to prevent alert fatigue - Severity mapping: EOL SDKs trigger
error, outdated SDKs triggerwarning - Rich context: Custom details show specific projects and environments affected
- Actionable: Each alert focuses on a single SDK type for clear ownership
CI/CD integration
Integrate SDK version checks into your CI/CD pipeline:
# GitHub Actions example
name: Check SDK Versions
on:
schedule:
- cron: '0 9 * * 1' # Weekly on Monday at 9 AM
workflow_dispatch:
jobs:
check-versions:
runs-on: ubuntu-latest
steps:
- name: Check SDK Versions
run: |
response=$(curl -s \
-H "Authorization: ${{ secrets.LD_API_TOKEN }}" \
-H "LD-API-Version: beta" \
https://app.launchdarkly.com/api/v2/usage/sdk-versions/details)
echo "$response" | jq -r '.[] | select(.eolStatus and .eolStatus != "EolAllClear" and .eolStatus != "EolUnknown") |
"\(.name) v\(.version) in \(.projectKey)/\(.environmentKey) - EOL: \(.eolStatus)"'
Real-world examples
The following examples use actual data from a LaunchDarkly account to demonstrate practical SDK version analysis.
Example API response structure
The API returns detailed information about each SDK instance. Here is a sample response showing the data structure:
[
{
"name": "Python Server SDK",
"version": "9.8.0",
"type": "server",
"projectId": "aaaaaaaaaaaaaaaaaaaaaaaa",
"projectKey": "api-backend",
"projectName": "API Backend",
"environmentId": "bbbbbbbbbbbbbbbbbbbbbbbb",
"environmentKey": "production",
"environmentName": "Production",
"applicationId": "api-server-prod",
"ldLatestVersion": "9.11",
"eolStatus": "EolPast",
"latestReleaseUrl": "https://github.com/launchdarkly/python-server-sdk/releases/latest",
"connectionType": "direct",
"relayVersion": "",
"relayEolStatus": "",
"relayLatestVersion": "",
"relayLatestReleaseUrl": ""
},
{
"name": "React Web SDK",
"version": "0.2.4",
"type": "browser",
"projectId": "cccccccccccccccccccccccc",
"projectKey": "customer-portal",
"projectName": "Customer Portal",
"environmentId": "dddddddddddddddddddddddd",
"environmentKey": "production",
"environmentName": "Production",
"applicationId": "react-client-sdk",
"ldLatestVersion": "3.3",
"eolStatus": "MajorVersionAvailable",
"latestReleaseUrl": "https://github.com/launchdarkly/react-client-sdk/releases/latest",
"connectionType": "direct",
"relayVersion": "",
"relayEolStatus": "",
"relayLatestVersion": "",
"relayLatestReleaseUrl": ""
},
{
"name": "Node.js Server SDK",
"version": "9.10.5",
"type": "server",
"projectId": "eeeeeeeeeeeeeeeeeeeeeeee",
"projectKey": "mobile-app",
"projectName": "Mobile Application",
"environmentId": "ffffffffffffffffffffffff",
"environmentKey": "production",
"environmentName": "Production",
"applicationId": "NodeJSClient",
"ldLatestVersion": "9.9",
"eolStatus": "EolAllClear",
"latestReleaseUrl": "https://github.com/launchdarkly/js-core/releases/latest",
"connectionType": "direct",
"relayVersion": "",
"relayEolStatus": "",
"relayLatestVersion": "",
"relayLatestReleaseUrl": ""
}
]
Analyzing relay proxy version distribution
A common scenario is identifying which relay proxy versions are deployed across your infrastructure. This example shows an organization with 41 relay proxy instances distributed across two versions:
import requests
from collections import defaultdict
url = "https://app.launchdarkly.com/api/v2/usage/sdk-versions/details"
headers = {
"Authorization": "api-your-access-token",
"LD-API-Version": "beta"
}
response = requests.get(url, headers=headers)
sdk_versions = response.json()
# Analyze relay proxy distribution
relay_by_version = defaultdict(list)
for sdk in sdk_versions:
if sdk['name'] == 'LDRelay':
relay_by_version[sdk['version']].append({
'project': sdk['projectKey'],
'environment': sdk['environmentKey']
})
# Display results
print("Relay Proxy Version Distribution:")
print("=" * 60)
for version, instances in sorted(relay_by_version.items()):
print(f"\nVersion {version}: {len(instances)} instances")
print(f"Sample deployments:")
for inst in instances[:5]:
print(f" - {inst['project']}/{inst['environment']}")
Sample output:
Relay Proxy Version Distribution:
============================================================
Version 8.17.3: 38 instances
Sample deployments:
- mobile-demo/production
- mobile-demo/test
- stream-service/production
- api-gateway/test
- customer-portal/production
Version 8.17.4: 3 instances
Sample deployments:
- core-platform/production
- core-platform/test
- core-platform/dev
Analysis: This output reveals that 38 relay proxy instances are running version 8.17.3, while only 3 have been upgraded to 8.17.4. This indicates a potential upgrade opportunity to standardize on the newer version.
Identifying version drift across environments
Version drift occurs when different environments run different SDK or relay proxy versions. This can lead to inconsistent behavior and makes troubleshooting difficult.
import requests
from collections import defaultdict
url = "https://app.launchdarkly.com/api/v2/usage/sdk-versions/details"
headers = {
"Authorization": "api-your-access-token",
"LD-API-Version": "beta"
}
response = requests.get(url, headers=headers)
sdk_versions = response.json()
# Track versions per project
project_versions = defaultdict(lambda: defaultdict(set))
for sdk in sdk_versions:
project_versions[sdk['projectKey']][sdk['name']].add(
(sdk['version'], sdk['environmentKey'])
)
# Find projects with version drift
print("Projects with version drift:")
print("=" * 60)
for project, sdks in sorted(project_versions.items()):
for sdk_name, versions in sdks.items():
unique_versions = set(v[0] for v in versions)
if len(unique_versions) > 1:
print(f"\n{project} - {sdk_name}:")
for version in sorted(unique_versions):
envs = [v[1] for v in versions if v[0] == version]
print(f" v{version}: {', '.join(envs)}")
Sample output:
Projects with version drift:
============================================================
mobile-demo - LDRelay:
v8.17.3: production, test
v8.17.4: staging
api-gateway - Node.js Server SDK:
v9.8.1: production
v9.10.2: test, dev
Recommendation: Standardize on a single version across environments within each project to ensure consistent behavior and simplify troubleshooting.
SDK inventory report
Generate a comprehensive report of all SDKs in use across your organization:
import requests
from collections import defaultdict
url = "https://app.launchdarkly.com/api/v2/usage/sdk-versions/details"
headers = {
"Authorization": "api-your-access-token",
"LD-API-Version": "beta"
}
response = requests.get(url, headers=headers)
sdk_versions = response.json()
# Summarize SDK usage
print("SDK Inventory Report")
print("=" * 80)
print(f"\nTotal SDK instances: {len(sdk_versions)}")
print(f"Unique projects: {len(set(s['projectKey'] for s in sdk_versions))}")
print(f"Unique environments: {len(set(s['environmentKey'] for s in sdk_versions))}")
# SDK breakdown
sdk_counts = defaultdict(set)
for sdk in sdk_versions:
sdk_counts[sdk['name']].add(sdk['version'])
print("\nSDK Distribution:")
print("-" * 80)
for sdk_name, versions in sorted(sdk_counts.items()):
count = sum(1 for s in sdk_versions if s['name'] == sdk_name)
print(f"{sdk_name}:")
print(f" Instances: {count}")
print(f" Versions: {', '.join(sorted(versions))}")
# Show EOL status if available
sample = next(s for s in sdk_versions if s['name'] == sdk_name)
if sample.get('eolStatus') and sample['eolStatus'] != 'EolUnknown':
print(f" EOL Status: {sample['eolStatus']}")
print()
# Environment coverage
env_counts = defaultdict(int)
for sdk in sdk_versions:
env_counts[sdk['environmentKey']] += 1
print("\nEnvironment Coverage:")
print("-" * 80)
for env, count in sorted(env_counts.items(), key=lambda x: -x[1]):
print(f"{env}: {count} SDK instances")
Sample output:
SDK Inventory Report
================================================================================
Total SDK instances: 46
Unique projects: 17
Unique environments: 8
SDK Distribution:
--------------------------------------------------------------------------------
.NET Server SDK:
Instances: 1
Versions: 8.11.1
EOL Status: EolAllClear
Go Server SDK:
Instances: 1
Versions: 7.14.6
EOL Status: EolAllClear
LDRelay:
Instances: 41
Versions: 8.17.3, 8.17.4
Node.js Server SDK:
Instances: 2
Versions: 9.10.2
EOL Status: EolAllClear
Python Server SDK:
Instances: 1
Versions: 9.14.1
EOL Status: EolAllClear
Environment Coverage:
--------------------------------------------------------------------------------
production: 19 SDK instances
test: 17 SDK instances
dev: 4 SDK instances
sit: 2 SDK instances
qa: 1 SDK instances
Insights from this data:
- Relay proxy is the most deployed component (41 instances)
- Production and test environments have the highest SDK coverage
- Most server-side SDKs show healthy EOL status
- Version standardization opportunity exists for relay proxy
Finding projects without SDK coverage
Identify projects that may not have SDK instrumentation:
import requests
# Fetch all projects (requires separate API call)
projects_url = "https://app.launchdarkly.com/api/v2/projects"
sdk_url = "https://app.launchdarkly.com/api/v2/usage/sdk-versions/details"
headers = {
"Authorization": "api-your-access-token",
"LD-API-Version": "beta"
}
# Get all projects
projects_response = requests.get(projects_url, headers=headers)
all_projects = set(p['key'] for p in projects_response.json()['items'])
# Get projects with SDK usage
sdk_response = requests.get(sdk_url, headers=headers)
projects_with_sdks = set(s['projectKey'] for s in sdk_response.json())
# Find projects without SDK instrumentation
projects_without_sdks = all_projects - projects_with_sdks
print(f"Projects without active SDK usage: {len(projects_without_sdks)}")
for project in sorted(projects_without_sdks):
print(f" - {project}")
This helps identify projects that may need SDK implementation or where SDKs have not reported telemetry recently.
Best practices
Monitor regularly
Schedule regular checks of SDK versions:
- Run automated checks weekly or monthly
- Alert teams when EOL SDKs are detected
- Track upgrade progress over time
Prioritize upgrades
Focus upgrade efforts based on risk:
- Critical: SDKs past end-of-life with known security issues
- High: SDKs approaching end-of-life
- Medium: SDKs more than two major versions behind
- Low: SDKs one minor version behind
Document versions
Maintain documentation of SDK versions:
- Record which versions are approved for use
- Document known issues with specific versions
- Track upgrade timelines and dependencies
Test upgrades
Test SDK upgrades thoroughly:
- Review release notes for breaking changes
- Test in non-production environments first
- Monitor error rates and performance after upgrading
- Have rollback plans ready
To learn more about SDK implementation best practices, read Preflight Checklist. To learn more about maintaining resilient SDK implementations, read Resilient SDK Implementation.