Awesome-omni-skill upgrade-integration
Integrate Carnegie Learning's UpGrade A/B testing platform into LMS and EdTech applications. Guides setup of decision points, experiment conditions, LTI/xAPI integration, and outcome logging. Use when asked to add A/B testing, experiments, or feature flags to educational software.
git clone https://github.com/diegosouzapw/awesome-omni-skill
T=$(mktemp -d) && git clone --depth=1 https://github.com/diegosouzapw/awesome-omni-skill "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/development/upgrade-integration" ~/.claude/skills/diegosouzapw-awesome-omni-skill-upgrade-integration && rm -rf "$T"
skills/development/upgrade-integration/SKILL.mdUpGrade A/B Testing Integration for EdTech
You are helping integrate UpGrade, Carnegie Learning's open-source A/B testing platform designed specifically for educational technology.
When This Skill Applies
- Adding A/B testing or experiments to educational apps
- Integrating feature flags in learning platforms
- Connecting EdTech apps to LMS via LTI with experiment support
- Setting up learning analytics with xAPI + experimentation
- Debugging experiment assignment issues
Critical Context
UpGrade is NOT a generic A/B testing tool. It's designed for education with features like:
- Group-level assignment (whole classrooms get same condition)
- Consistency rules (students don't get re-randomized)
- Educational context metadata (grade, subject, proficiency)
ALWAYS ask these questions before implementing:
- What's the assignment unit? (Individual student vs classroom vs school)
- What happens if a student changes classes mid-experiment?
- How will teachers access both conditions (or will they)?
- Is the app used in LMS iframes? (Cookie issues!)
Quick Reference
Installation
# JavaScript/TypeScript npm install upgrade_client_lib # Java (Maven) <dependency> <groupId>com.carnegielearning</groupId> <artifactId>upgrade-client</artifactId> </dependency>
Core Integration Pattern
import UpgradeClient from 'upgrade_client_lib/dist/browser'; import { MARKED_DECISION_POINT_STATUS } from 'upgrade_client_lib'; // 1. Initialize (MUST complete before getDecisionPointAssignment) const client = new UpgradeClient(userId, hostUrl, context); await client.init(groupData, workingGroupData); // 2. Get assignment at decision point const assignment = await client.getDecisionPointAssignment('feature_name', 'target'); const condition = assignment.getCondition(); const payload = assignment.getPayload(); // 3. Mark that condition was applied client.markDecisionPoint('feature_name', MARKED_DECISION_POINT_STATUS.CONDITION_APPLIED); // 4. Log outcomes client.log('score', 85); client.log('completion_time_ms', 45000);
Three SDK Modes
| Mode | Use Case | Requires init()? |
|---|---|---|
| Standard | Pre-registered users with stored groups | Yes |
| Ephemeral | Runtime-provided groups, no DB lookup | No |
| Merged | Combine session + stored groups | Yes |
Integration Architecture
┌─────────────────────────────────────────────────────────────┐ │ LMS │ │ (Canvas, Moodle, etc.) │ └─────────────────────┬───────────────────────────────────────┘ │ LTI 1.3 Launch │ (user_id, context_id, roles) ▼ ┌─────────────────────────────────────────────────────────────┐ │ Your EdTech App │ │ ┌─────────────────────────────────────────────────────┐ │ │ │ Identity Mapper │ │ │ │ LTI user_id → UpGrade userId + altUserIds │ │ │ └─────────────────────┬───────────────────────────────┘ │ │ │ │ │ ┌─────────────────────▼───────────────────────────────┐ │ │ │ UpGrade SDK │ │ │ │ - init(groupData) │ │ │ │ - getDecisionPointAssignment() │ │ │ │ - markDecisionPoint() │ │ │ │ - log() │ │ │ └─────────────────────┬───────────────────────────────┘ │ └─────────────────────────┼───────────────────────────────────┘ │ HTTPS ▼ ┌─────────────────────────────────────────────────────────────┐ │ UpGrade Backend │ │ (Self-hosted or Carnegie Learning) │ └─────────────────────────────────────────────────────────────┘
CRITICAL: Known Pitfalls
Before writing ANY integration code, read
resources/pitfalls-and-edge-cases.md. The most dangerous issues:
1. Third-Party Cookie Blocking (CRITICAL)
If your app runs in an LMS iframe, Safari and Chrome WILL block your session cookies by default.
Symptoms:
- User gets re-randomized on every page load
seems to work but assignments are inconsistentinit()- Works in development, fails in production LMS
Solutions:
- Set
on all cookiesSameSite=None; Secure - Use localStorage with user-provided identifier (not session-based)
- Consider opening in new window instead of iframe
2. Race Condition: init() vs getDecisionPointAssignment()
// WRONG - race condition const client = new UpgradeClient(userId, hostUrl, context); client.init(groupData); // async, not awaited! const assignment = await client.getDecisionPointAssignment('feature'); // assignment may be NO_CONDITION_ASSIGNED
// CORRECT const client = new UpgradeClient(userId, hostUrl, context); await client.init(groupData); // AWAIT this! const assignment = await client.getDecisionPointAssignment('feature');
3. LTI Identity Mismatch
LTI provides
user_id which is opaque and LMS-specific. Your app may use email or internal IDs.
// Map all identities together await client.init(groupData); client.setAltUserIds([ ltiUserId, // from LTI launch userEmail, // from your auth internalDatabaseId // your user table PK ]);
4. Group Assignment Drift
Student transfers from Mrs. Smith's class (Treatment A) to Mr. Jones' class (Treatment B).
Default behavior: Student KEEPS original assignment (consistency rule)
Problem: Student now sees different UI than classmates, causing confusion.
Solution: Decide upfront:
- Accept drift (experimental purity)
- Re-assign on class change (classroom consistency)
- Exclude transferred students from analysis
5. Shared Device / Chromebook Cart Problem
// WRONG - userId persists from previous student const client = new UpgradeClient(getUserIdFromLocalStorage(), ...); // CORRECT - validate identity on each session const client = new UpgradeClient(getCurrentAuthenticatedUserId(), ...); // Clear any cached assignments if userId changed
Decision Point Patterns for Education
See
resources/decision-point-patterns.md for detailed examples:
| Pattern | Example | Assignment Unit |
|---|---|---|
| UI Variant | New vs old problem interface | Individual |
| Pedagogical | Worked examples vs practice problems | Classroom |
| Adaptive Algorithm | Mastery threshold 80% vs 90% | Individual |
| Content Ordering | Teach fractions before decimals vs after | School |
| Feedback Timing | Immediate vs delayed feedback | Classroom |
Code Templates
See
templates/ directory for:
- React hook with proper error handlingreact-hook.tsx
- Next.js API route patternnextjs-middleware.ts
- Framework-agnostic implementationvanilla-js.js
- LTI 1.3 launch with UpGrade initlti-launch-handler.ts
Logging Best Practices
// DO: Use consistent types client.log('score', 85); // number client.log('completed', true); // boolean client.log('response', 'correct'); // string // DON'T: Mix types for same metric client.log('score', 85); client.log('score', '85'); // String! Will corrupt analysis // DON'T: Log before marking decision point client.log('score', 85); // Not associated with condition! client.markDecisionPoint('quiz', MARKED_DECISION_POINT_STATUS.CONDITION_APPLIED); // DO: Mark first, then log client.markDecisionPoint('quiz', MARKED_DECISION_POINT_STATUS.CONDITION_APPLIED); client.log('score', 85); // Correctly associated
Troubleshooting Decision Tree
Assignment returns NO_CONDITION_ASSIGNED ├── Did you await init()? │ └── No → Add await before init() ├── Is experiment in ENROLLING state? │ └── No → Check UpGrade UI, start experiment ├── Does user match segment criteria? │ └── No → Check inclusion/exclusion rules ├── Is context correct? │ └── No → Verify context string matches experiment config └── Check network tab for failed requests
User gets different condition than classmates ├── Is assignment unit set to GROUP? │ └── No → Change to GROUP in experiment settings ├── Was groupData provided to init()? │ └── No → Pass { classId: 'xxx' } to init() ├── Did student join after experiment started? │ └── Yes → Check POST_EXPERIMENT_RULE └── Is student in multiple groups? └── Yes → Check group priority/override logic
External Resources
When to Escalate
Recommend the developer contact UpGrade support or file a GitHub issue if:
- Assignment algorithm seems incorrect (statistical anomaly)
- Data export shows impossible values
- Backend returns 5xx errors consistently
- Need custom consistency rules not supported by SDK