⌘K
↑↓ Navigate ↵ Open Esc Close
Appendix

Documented, not yet exercised

Features with real API surface and real documentation, but no reference app in this repo uses them yet. Included for review, cited to brainCloud's own API docs rather than to a repo file and line.

Appendix ACampaign

Campaign: schedule the change once, let it start and stop itself

Global Properties and Item Catalog & Store are the two systems a campaign actually reaches into. Player State & User Data has the UpdateIsTester call you need before you can force-enroll a QA account.

Read this one differently than the rest of the series. Every other article here cites real, working code from a reference app in this repo. This one can't, because nothing in this repo uses brainCloud's Campaign service, checked against both the client source and the actual cloud-code scripts running in the reference apps' brainCloud accounts. It's written up anyway, for review purposes, grounded directly in brainCloud's own API documentation and verified live against it (via the brainCloud MCP server), not written from memory of what Campaign probably does. Treat the code below as "this is the documented structure of the API," not "this is how our apps use it."

Campaign is brainCloud's mechanism for running a scheduled promotion or A/B test without a build or a manual switch once it's live. A campaign is configured in the portal once: a start and end time, the player segment it targets, one or more weighted scenarios (a scenario is a variant, and one of them can be the untouched "control" group), and a set of overrides each scenario applies. From that point, the campaign runs itself: it starts on schedule, enrolls eligible players into a scenario, applies that scenario's overrides to what those players see, tracks basic engagement metrics per player, and expires on schedule. The client's whole job is one call after login to ask "what am I enrolled in," then apply whatever comes back exactly the way it already applies Global Properties.

How it works

  1. A campaign's overrides sit directly on top of systems this series already covers. The response from GetMyCampaigns carries an overrides block that can replace values in globalProperties (the same system Article 11 reads directly), cashProducts (real-money price points, the App Store side of Article 10), and items (virtual-currency buyPrice, the Item Catalog side of the same article). A campaign isn't a fourth, separate config system. It's a scheduled, segment-targeted layer that temporarily overrides the three systems already covered.
  2. The client makes one call, typically right after login, and gets back everything it needs to apply those overrides. GetMyCampaigns returns every campaign the current player is enrolled in, including which scenario the player landed in, the campaign's own free-form campaignJson payload, the scenario's own scenarioJson payload, and the overrides block itself. There's no separate "check eligibility" call; enrollment already happened server-side before this response exists.
  3. Which scenario a player lands in is a weighted, one-time assignment, not something the client requests. A campaign can define several scenarios, one of which can be a "control" variant that changes nothing, and the server randomly assigns each newly eligible player to one, honoring whatever weights the portal has configured. Once assigned, a player stays in that scenario for the life of the campaign.
  4. Live edits to a campaign's payload don't require a version bump or a client update. SysUpdateCampaignJson and SysUpdateScenarioJson (Cloud Code / S2S only) replace just the free-form JSON payload, leaving the schedule, targeting, and scenario weights untouched. Already-authenticated players pick up the new payload on their very next GetMyCampaigns call. That's the mechanism for hot-fixing campaign copy or config mid-run, without touching the campaign's actual A/B structure.
  5. Forcing a specific player into a specific scenario is a QA tool, not a general-purpose override, and it's gated behind a real profile flag. SysTriggerCampaignForUser can push a chosen scenario onto a specific player, bypassing the normal weighted assignment, but only if that player's profile already has isTester=true set. There's no way to force-enroll an arbitrary live player. A QA flow built around this needs PlayerState.UpdateIsTester (Article 8) run against the test account first.
  6. This is a billing-gated feature, not just an SDK class everyone can use. Every Campaign method's error list carries the same code: FEATURE_NOT_SUPPORTED_BY_BILLING_PLAN, requiring a plan that includes Enterprise features. That's worth knowing before designing around it. A reference app on a lower-tier plan couldn't exercise this even if someone wrote the client code today.

Code

The one client call: ask what campaigns you're enrolled in (JavaScript)
var optionsJson = {};
_bc.campaign.getMyCampaigns(optionsJson, result =>
{
  var status = result.status;
  console.log(status + " : " + JSON.stringify(result, null, 2));
});
What comes back, trimmed to the interesting fields
{
  "data": {
    "campaigns": [
      {
        "campaignCode": "holiday2026",
        "scenarioCode": "b",
        "startAt": 1714000000000,
        "endAt": 1716591999000,
        "targetType": "SEGMENT",
        "segmentCode": "premium_users",
        "campaignJson": { "theme": "summer" },
        "scenarioJson": { "discount": "50%" },
        "loginCount": 12,
        "numPurchases": 2,
        "amtSpent": 499,
        "overrides": {
          "globalProperties": {
            "free_currency_bonus": { "name": "free_currency_bonus", "value": "200" }
          },
          "cashProducts": {
            "coinbundle10": { "itemId": "coinbundle10", "priceId": 1 }
          },
          "items": {
            "sword_01": { "defId": "sword_01", "buyPrice": { "coins": 50 } }
          }
        }
      }
    ]
  },
  "status": 200
}
Hot-fixing a campaign's payload without touching its schedule or targeting (Cloud Code)
var campaignCode = "CHRISTMAS2026";
var version = -1;   // -1 = apply regardless of the current version
var campaignJson = { "theme": "winter", "bannerId": 7 };
var campaignProxy = bridge.getCampaignServiceProxy();

var postResult = campaignProxy.sysUpdateCampaignJson(campaignCode, version, campaignJson);
// postResult.data.version is the new version; feed it back in next time
// if you want a concurrent-edit check instead of a blind overwrite
Forcing a QA account into a specific scenario (Cloud Code)
var profileId = "aProfileId";        // this profile must already have isTester=true
var campaignCode = "CHRISTMAS2026";
var optionsJson = {
  "ignoreEnabled": false,
  "ignoreScheduleStart": false,
  "ignoreControl": false,
  "scenarioCode": "a"                // skip weighted assignment, force this exact scenario
};
var campaignProxy = bridge.getCampaignServiceProxy();

var postResult = campaignProxy.sysTriggerCampaignForUser(profileId, campaignCode, optionsJson);

Best practices worth flagging up front

  • Design the overrides against systems the client already has a read path for. A client that doesn't already know how to apply a globalProperties override (Article 11) or a catalog/store price override (Article 10) gains a fourth thing to build by adding Campaign on top, not a free one. Get those two solid first.
  • campaignJson is broadcast to every enrolled player, so it shouldn't hold anything a client isn't meant to see. It's returned in full on every GetMyCampaigns call. There's also a real size cap, enforced server-side, so it should stay a small config payload, not a place to stash content.
  • Use the version parameter as an optimistic-concurrency check once more than one person can edit a campaign. Passing the campaign's last-known version instead of -1 means a concurrent edit from the portal (or another script) surfaces as CAMPAIGN_VERSION_MISMATCH instead of silently getting overwritten.
  • Flag the test account isTester=true before touching anything Campaign-specific. SysTriggerCampaignForUser refuses to run against a player who isn't flagged. Set that in test setup before the scenario-forcing step, or the force-enroll call fails with a permissions-shaped error that has nothing to do with the campaign itself.
  • Confirm the billing plan actually includes Campaign before designing a feature around it. FEATURE_NOT_SUPPORTED_BY_BILLING_PLAN is the one error code every single method in this service shares. It's an Enterprise-tier feature, not something available by default.