Part 1: Getting Started with Adobe Campaign – Campaigns, Workflows, and Best Practices
Adobe Campaign isn’t just a delivery engine. It’s a programmable orchestration layer that allows you to operationalize audience segmentation, campaign delivery, and reporting across geographies and product lines.
In this post, we’ll walk through how to launch your first Adobe Campaign project from the ground up using best-in-class conventions.
Step 1: Campaign Setup
Create a campaign in the desktop client under:
Campaign Management > Programs > Your Team Folder > Campaigns
Example naming convention:
Label: Type_Business_Campaign_Name_Date (e.g., MKT_EDU_Onboarding_2025Q1)
Select Simple Batch Campaign as the template.
Step 2: Workflow Configuration
Within your campaign, add a workflow named Main_Email_Workflow. Add and configure the following activities:
- Schedulers (x4): If your audience is global, you’ll likely need to send emails during working hours for each major region. As an example, you can configure four schedulers—one each for EMEA, NAMER, LATAM, and APAC. These schedulers all use Pacific Time (the server time zone), but their execution times are set to match optimal delivery windows for each region. If you have more granular segmentation (e.g., 8 regional markets), you can increase the number of schedulers accordingly. The principle is simple: trigger email sends when they are most likely to be opened, but centralize timing in the server’s native time zone to avoid DST drift and scheduling errors.
- JavaScript Node: This is your workflow’s control logic. Use it to:
- Validate audience freshness: For example, confirm that your uploaded audience list was refreshed within the past 3 days. You can calculate this by comparing a lastModifiedDate variable to new Date() minus a 3-day offset, and set a flag like vars.validRunFlag accordingly. If that flag is false, the scheduler can be prevented from continuing the flow.
- State-based routing: In workflows that execute hourly or daily based on some external flag, use getOption(“campaignStep”) to retrieve state and use setOption(“campaignStep”, newValue) to increment it per iteration.
- Debugging and Logging: Always add logInfo(“Running JS Checkpoint”) lines to observe control flow in execution logs.
- Read List: Connect this node to either a manually uploaded static list or a dynamically generated recipient query. This node pulls in your population for the current run.
- Enrichment: Join additional data—like region, language, or user-level flags—from linked schemas. Also, define personalization and reporting fields here such as @contentAssignment, @subjectLine, or @emailVariantFlag.
- Split: Route audiences based on region, priority, or behavior (e.g., opens/clicks). Each branch can flow to a different delivery or suppression rule.
- Delivery: Attach your approved HTML template or PSN blocks, enable proofing, and set up any conditional logic within the delivery itself.
Implementation Tips
- Always stage and test your workflow.
- Use Display Targeting to preview record sets at every stage.
- Label your nodes and transitions clearly.
- Ensure your delivery logs have the fields required for downstream dashboards.
Part 2: Workflow Engineering in Adobe Campaign – Structure, Logic, and Scale
Once your basic campaign flow is functional, it’s time to scale your implementation by using modular, reusable, and logic-driven workflows. The more consistent and structured your workflows are, the more predictable your campaign outcomes will be.
Let’s break down four proven patterns that scale well across enterprise marketing needs.
Pattern 1: Multi-Touch Evergreen Campaign
- Goal: Send a series of emails (Initial → Reminder → Completion Follow-up) triggered by audience behavior.
- Workflow Structure:
- Multiple Scheduler nodes set to regional time zones to support geo-specific sends.
- JavaScript node checks if the target list was updated recently using a last-modified date. If not, the send is skipped to prevent sending outdated content.
- Read List pulls a weekly or daily refreshed audience file.
- Enrichment node joins with a personalization or activity history table.
- Split branches audiences based on recent open/click or conversion.
- Three Delivery nodes: Initial → Reminder → Completion-specific message.
- Deduplication and Broadlog filters prevent duplicate messaging within a defined lookback window (e.g., 30 days).
Pattern 2: Priority-Based Hourly Campaign
- Goal: Stagger sends over 24 hours based on a member’s intent or priority score.
- Workflow Structure:
- Scheduler runs every hour on the hour.
- JavaScript retrieves the current priority tier from a stored option value (e.g., getOption(“priorityTier”)).
- Read List pulls the full audience list and filters based on priority = vars.priorityTier.
- Delivery fires, then JavaScript increments the option (e.g., setOption(“priorityTier”, nextTier)).
- This pattern continues until all priority tiers have been processed.
Pattern 3: Personalized Abandonment Workflow
- Goal: Trigger an abandonment email once per quarter, with dynamic behavior-based content.
- Workflow Structure:
- Weekly Scheduler initiates the workflow.
- Read List queries a personalization schema for users with incomplete activity.
- JavaScript filters or suppresses audiences with recent conversions.
- Enrichment dynamically sets personalization flags like product category or timestamp of abandonment.
- Delivery uses PSN blocks to fill in content relevant to the user’s activity.
Pattern 4: Reporting and Auditing Workflow
- Goal: Generate an automated weekly CSV of campaign performance across all sends.
- Workflow Structure:
- Scheduler triggers Monday morning.
- Query pulls delivery logs for the previous 7 days (BroadlogRcp, TrackingLogRcp).
- Enrichment joins metadata like campaign name, variant, and region.
- JavaScript formats metrics and optionally applies thresholds or filters.
- Data Extraction (fileExport) writes to .csv and drops the file to an SFTP server or local export path.
Key Workflow Best Practices
- Use Option Variables: Ideal for long-running or iterative workflows (e.g., hourly send queues, multi-day journeys).
- JavaScript Logic: Your best tool for pre-checks, conditional routing, and fallback logic. Use logs to understand failures.
- Display Targeting Mode: Always test in Display Target to confirm joins, filters, and flag logic are working.
- Label Everything: Be explicit. Name your nodes after what they do—not just “Split-1” or “JS-2.” Future-you (or your coworkers) will thank you.
For more examples of Workflows check out How to bulk import html files as Personalization Blocks in Adobe Campaign v8 or Migrating Content from Responsys to Adobe Campaign Using Python
Part 3: Enrichment and Reporting – Personalization that Scales
Personalization in Adobe Campaign is only as powerful as the metadata you assign to your recipients during workflow execution. Contrary to some assumptions, Adobe Campaign does not automatically populate delivery logs with subject lines or content variant identifiers. You must explicitly assign those values through Enrichment before your Delivery node.
Why Enrichment Matters for Reporting
Enrichment allows you to:
- Join additional data to your target audience (e.g., locale, past behavior, campaign metadata)
- Calculate fields dynamically using expressions (like Iif() conditions)
- Populate alias fields such as @contentAssignment, @subjectLine, or @variantFlag for downstream analytics
These fields can be surfaced in dashboards, exported reports, or used for A/B testing evaluations. If you don’t set them, they don’t exist.
Example: Nested Iif() for Language-Based Assignment
Say you have an audience segmented by language ID. You want each language group to get a different subject line and have that recorded in the logs. You’d configure the Enrichment node with expressions like:
Iif(user_language_id = 74, 'del_IT_OnboardingWebinar',
Iif(user_language_id = 68, 'del_FR_OnboardingWebinar',
Iif(user_language_id = 34, 'del_DE_OnboardingWebinar',
'del_EN_OnboardingWebinar')))
Map this expression to a field aliased as @contentAssignment.
Example: Subject Line Assignment
Iif(user_language_id = 74, 'Benvenuto a bordo!',
Iif(user_language_id = 68, 'Bienvenue à bord!',
Iif(user_language_id = 34, 'Willkommen an Bord!',
'Welcome aboard!')))
Map this to the @subjectLine alias.
Best Practices
- Keep all logic in one centralized Enrichment node pre-Delivery.
- Always use clear field aliases so your reporting queries and dashboards stay consistent.
- If you’re using PSN blocks to inject personalized content, still assign @contentAssignment to tag what was shown.
Common Pitfalls
- Forgetting to assign these fields causes blank or default values in your dashboards.
- Over-nesting Iif() statements can lead to errors. Keep them readable.
- Validate with Display Target before every delivery. Preview values of @subjectLine, @contentAssignment, etc.
Part 4: Building Transactional Messaging with Message Center
Message Center is Adobe Campaign’s transactional messaging engine. It’s used for sending emails triggered by real-time events—like purchase confirmations, password resets, or onboarding flows.
These are different from marketing campaigns in several ways:
- The email is triggered by an API call.
- The recipient is defined in the payload.
- All personalization must be passed in the payload (no lookup from the database).
Step 1: Build the Template
Navigate to:
Resources > Templates > Message Center > Transactional Message Templates
Create a new template:
- Label: Give it a human-readable name (e.g., Order_Confirmation_Template)
- Event Type: Must match the event name you will use in the SOAP payload
Design the email as usual, but all dynamic values must come from the rtEvent.ctx object. For example:
Hi <%= rtEvent.ctx.firstName %>,
Thank you for your order. Your confirmation number is <%= rtEvent.ctx.orderId %>.
Step 2: Proof and Publish
- Click the Proof button to simulate a test event
- Use a mock payload or predefined test values
- Once verified, click Publish to replicate the template to the RT instance
You cannot use database-driven personalization here. Everything must be in the payload.
Step 3: Send a Live Test via Postman
Use Postman or a similar tool to test the SOAP API:
<rtEvent email="demo@example.com" type="Order_Confirmation_Template" externalId="123456">
<ctx>
<firstName>Jordan</firstName>
<orderId>78910</orderId>
</ctx>
</rtEvent>
POST to:
https://your-rt-stage-url.campaign.adobe.com/nl/jsp/soaprouter.jsp
With headers:
- SOAPAction: nms:rtEvent#PushEvent
- Content-Type: text/xml;charset=UTF-8
Step 4: Debug and Monitor
Go to Administration > Message Center > Event History. Here you can see:
- Timestamps of when messages were received and processed
- CTX values
- Status (sent, failed, processing)
Use this to confirm that:
- The correct event type was used
- Payload values resolved properly in the delivery
Final Tips
- Keep event type names lowercase and underscored (e.g., event_registration)
- Seed addresses receive the message only once—on first publish
- Templates must be re-published if updated (no automatic sync)
- Use logs and Event History for debugging payload mismatches
Part 5: A/B Testing the Right Way in Adobe Campaign
If you’re not applying rigorous logic and analytics to your A/B tests in Adobe Campaign, you’re wasting audience reach and budget. Here’s how to design a proper A/B test in a reusable, data-driven workflow.
A/B Testing Overview
True A/B testing involves:
- Randomly sampling your audience into two (or more) groups
- Sending a different variant to each group
- Capturing and tagging metadata like variant ID, subject line, and content assignment
- Measuring performance downstream using your reporting dashboards
Why PSN Blocks Matter
Rather than building separate HTMLs for each variant, we use Personalization Blocks (PSN) to inject variant-specific content into a shared template. This reduces duplication and ensures centralized control.
Step-by-Step A/B Workflow
- Scheduler: Triggers the campaign at a scheduled time
- Read List: Loads your audience from a static list or query
- Enrichment (Pre-Split):
- Adds personalization fields
- Defines a randomized test flag (if needed)
- Assigns placeholder values for @contentAssignment and @subjectLine
- Split Node:
- 50/50 split (or other ratio if testing more than 2 variants)
- Each branch receives a different PSN content or subject line
- Deliveries:
- Use the same template with dynamic PSN block referencing variant name
- Match delivery label and internal name to variant (e.g., Email_Variant_A, Email_Variant_B)
- Enrichment (Post-Split):
- Assign final @contentAssignment and @subjectLine values explicitly
- Optional: tag audience record with variantId, deliveryId, etc.
- Logging/Export (optional):
- Write results to a log table or extract for analytics
Sample Content Assignment Expression
Iif(@testFlag = ‘A’, ‘Variant_A’, ‘Variant_B’)
Proofing
Before launching:
- Use Display Target to verify each branch’s records
- Send proofs from both variants using manual selection
- Confirm the subject line and PSN blocks render correctly
Dashboard Compatibility
- Ensure both variants are visible in dashboards
- Use @contentAssignment and @subjectLine to filter performance
- Confirm open/click metrics are populating properly in tracking logs
Part 6: Troubleshooting Adobe Campaign – Workflow Failures and Fixes
Nothing is more frustrating than a workflow that runs without actually doing what it’s supposed to do. Adobe Campaign offers minimal visibility by default—so your ability to troubleshoot comes down to structure, logging, and experience.
1. Enrichment Failures
- Symptoms: 0 recipients post-enrichment, even though Read List was populated
- Fixes:
- Check join conditions in the enrichment—are the foreign keys aligned?
- Use Display Target before the enrichment to verify incoming rows
- Add a test node to preview NULL values that could break joins
2. JavaScript Errors
- Symptoms: Workflow fails silently or throws cryptic PGS-220000 errors
- Fixes:
- Wrap logic in try/catch blocks
- Always include logInfo() outputs
- Avoid hardcoded dates unless you’re simulating something
- Ensure XML data like timestamps are formatted (.replace(‘ ‘, ‘T’))
3. Scheduler Issues
- Symptoms: Workflow doesn’t trigger, triggers too early, or fires inconsistently
- Fixes:
- Confirm timezone awareness (everything runs in server time)
- Ensure recurrence is enabled
- Validate day-of-week or exclusion filters
4. Delivery Failures
- Symptoms: Proofs won’t send, emails don’t show up, or personalization is blank
- Fixes:
- Verify typology rules are not blocking the delivery
- Enable “Display Errors” in Delivery logs
- Ensure the content has a subject line and unsubscribe footer
5. Message Center Fails
- Symptoms: RT event not triggered, wrong template used, or no delivery
- Fixes:
- Event Type must match exactly (case-sensitive)
- All ctx fields used in the template must be passed in payload
- Check Event History for failure cause
6. Missing Recipients
- Symptoms: Workflow executes but sends to 0 recipients
- Fixes:
- Double check filters or segment splits
- Confirm the input file isn’t empty or filtered out due to date checks
- Look at suppression joins and last send logic
Final Advice
- Add comments inside JavaScript nodes explaining business logic
- Maintain a library of reusable Enrichment expressions
- Run your QA in Display Target mode with real-time previews
- Use debug delivery templates that print all field values in the email body