Marketing Cloud Developer Interview Questions

25 expert-curated questions covering AMPscript, SSJS, REST/SOAP APIs, data views, and Automation Studio.

Marketing Cloud Developer Interview Questions

%%[ ]%% delimits a multi-line AMPscript code block where you can write SET, VAR, IF, and function calls. @variable is the variable reference syntax — variables are declared with VAR @name and assigned with SET @name = value. Outside a block you reference a variable inline as %%=@name=%%. You can also use inline expressions with %%=FunctionName(args)=%% without opening a full block. The key rule is that executable statements (SET, IF, FOR) must live inside %%[ ]%%, while output references can appear anywhere in the content using the %%=...=%% inline syntax.
VAR @name explicitly declares a variable, which is optional in most contexts — AMPscript will auto-declare on first SET. However, explicit VAR is recommended for clarity and is required in some strict server-side contexts (CloudPages with strict parsing). SET @name = expression assigns a value. Variables are page-scoped; they do not persist across send-time personalisation calls on different emails. Example: %%[ VAR @fname SET @fname = AttributeValue("FirstName") ]%% then output with Hello %%=@fname=%%.
Lookup returns a single scalar value — the value of the specified column from the first row matching the filter criteria. Syntax: Lookup("DE_Name","ReturnCol","FilterCol","FilterVal"). LookupRows returns a rowset object containing all matching rows. You iterate using Row(rowset, rowNum) and Field(row, "colName"). LookupOrderedRows returns a rowset sorted by a specified field (ascending or descending) and can be capped to a maximum row count. Use LookupOrderedRows when you need the most recent N records (e.g., last 3 purchases ordered by date descending).
AMPscript uses IF condition THEN ... ELSEIF condition THEN ... ELSE ... ENDIF for conditional logic. Conditions use comparison operators (==, !=, >, <) and logical operators (AND, OR, NOT). Example:
%%[
SET @tier = Lookup("Loyalty","Tier","Email",emailaddr)
IF @tier == "Gold" THEN
SET @msg = "Thank you, Gold member!"
ELSEIF @tier == "Silver" THEN
SET @msg = "Thank you, Silver member!"
ELSE
SET @msg = "Thank you for being a member!"
ENDIF
]%%
%%=@msg=%%

ENDIF is mandatory to close every IF block. Nested IFs are supported but can hurt readability.
FOR @i = startValue TO endValue DO ... NEXT @i iterates a counter variable. The most common use is iterating over a LookupRows or LookupOrderedRows rowset:
%%[
SET @rows = LookupRows("Orders","Email",emailaddr)
SET @cnt = RowCount(@rows)
FOR @i = 1 TO @cnt DO
SET @row = Row(@rows, @i)
SET @product = Field(@row, "ProductName")
]%%
%%=@product=%%<br>
%%[ NEXT @i ]%%

Note that AMPscript does not support WHILE loops. All iteration must be done via FOR/NEXT with a known upper bound (use RowCount to get it).
IIF(condition, trueVal, falseVal) — inline if/else in a single expression.
FormatDate(@date, "shortdate") — formats a date value; supports named patterns (shortdate, longdate) or custom patterns like "MM/DD/YYYY".
DateAdd(@date, numDays, "D") — adds units to a date; unit codes: D (days), M (months), Y (years), H (hours).
Substring(@str, start, length) — extracts characters; 1-based index.
Concat(str1, str2, ...) — concatenates strings.
Replace(@str, "find", "replace") — replaces all occurrences of a substring.
UpperCase(@str) — converts to uppercase; LowerCase and ProperCase also available.
Length(@str) — returns the number of characters in the string.
These AMPscript functions manipulate data extension records at send time (and on CloudPages):
InsertDE("DE", col1, val1, ...) — inserts a new row; returns 1 on success.
UpdateDE("DE", numMatchCols, matchCol, matchVal, updateCol, updateVal, ...) — updates matching rows; returns the number of rows updated.
UpsertDE("DE", numMatchCols, matchCol, matchVal, col, val, ...) — inserts or updates based on match; returns 1 for insert, number of rows updated for update.
DeleteDE("DE", numMatchCols, matchCol, matchVal) — deletes matching rows; returns the count of deleted rows.
ClaimRow("DE", returnCol, matchCol, matchVal) — atomically reserves a row (sets a flag) and returns the value of the specified column; used for one-time code distribution to prevent duplicate claims.
ContentArea(areaNumber) — retrieves a Classic Content Area by its numeric ID from the legacy Classic email content. Largely deprecated in favour of Content Builder.
ContentBlockByKey("externalKey") — retrieves a Content Builder content block by its Customer Key (External Key). This is the preferred method in modern implementations because keys are human-readable and portable across environments.
ContentBlockById(numericId) — retrieves a Content Builder content block by its internal numeric ID. Less portable because IDs differ between business units and environments.
Best practice: always use ContentBlockByKey in production for maintainability. Assign meaningful external keys in Content Builder when creating blocks.
RedirectTo(url) wraps a URL with Marketing Cloud click tracking and returns the tracked URL. To append UTM parameters you build the URL string first:
%%[
SET @baseUrl = "https://example.com/product"
SET @utm = "?utm_source=email&utm_medium=email&utm_campaign=spring2025"
SET @trackedUrl = RedirectTo(Concat(@baseUrl, @utm))
]%%
<a href="%%=@trackedUrl=%%">Shop Now</a>

The outer MC tracking layer records the click against the subscriber, and the UTM parameters are passed through to GA/analytics. Ensure special characters are URL-encoded using URLEncode() if parameter values contain spaces or special characters.
AttributeValue("attrName") retrieves a profile attribute or sendable data extension field value for the current subscriber being rendered. It looks up the value from the subscriber's profile attributes (All Subscribers list attributes) or, when sending from a data extension, from the columns in that DE. It is the fastest method for simple personalisation.
Lookup("DE", returnCol, matchCol, matchVal) performs an explicit query against any data extension. Use Lookup when you need to retrieve data from a non-sendable DE, a related record, or when you need fields not available on the subscriber's send record. Lookup incurs more processing overhead; cache results in variables when re-used multiple times in the same email.
AMPscript is a lightweight markup language designed for email personalisation. It is optimised for high-volume send-time rendering, has lower server overhead, and is the only scripting language supported inside email sends. Use AMPscript for email personalisation, DE lookups at send time, and simple conditional content.
SSJS (Server-Side JavaScript) runs on the Marketing Cloud application server. It supports modern JavaScript syntax, complex data structures, HTTP calls, and the full WSProxy/Core library. SSJS is available in CloudPages, Script Activities in Automation Studio, and landing pages, but not inside email sends. Use SSJS when you need API calls, complex logic, error handling, or cross-object data manipulation that exceeds AMPscript capabilities.
WSProxy is a SSJS library that wraps the SOAP API. Example patterns:
Retrieve: var prox = new Script.Util.WSProxy(); var cols = ["Name","CustomerKey"]; var response = prox.retrieve("DataExtension", cols);
Create: prox.createItem("DataExtensionObject", {CustomerKey:"DE_Key", Properties:[{Name:"Email",Value:"test@x.com"}]});
Update: prox.updateItem("DataExtensionObject", {CustomerKey:"DE_Key", Properties:[...]});
Delete: prox.deleteItem("DataExtensionObject", {CustomerKey:"DE_Key", Properties:[{Name:"SubscriberKey",Value:"123"}]});
Upsert: prox.upsertItem("DataExtensionObject", {...});
WSProxy handles authentication automatically using the context token, avoiding manual OAuth flows in Script Activities.
SSJS provides the HTTP object (on CloudPages) and Platform.Function.HTTPGet/HTTPPost for API calls from Script Activities:
HTTP.Get(url): Returns a string response. No header control.
HTTP.Post(url, contentType, body): Sends a POST request.
For full header control (needed for authenticated REST API calls) use HTTP.Get(url, headerNames[], headerValues[]) and HTTP.Post(url, contentType, body, headerNames[], headerValues[], statusCode).
PUT/DELETE: Use HTTP.Post with a header X-HTTP-Method-Override: PUT or DELETE, since SSJS HTTP does not have native PUT/DELETE methods. Alternatively, use WSProxy for SOAP-based operations or call Marketing Cloud's own REST endpoints via HTTP.Post with appropriate method overrides.
Marketing Cloud uses OAuth 2.0 client credentials flow for server-to-server authentication. Steps:
1. Create an Installed Package in Setup with a Server-to-Server component and assign required API scopes.
2. Obtain client_id and client_secret from the package.
3. POST to https://YOUR_SUBDOMAIN.auth.marketingcloudapis.com/v2/token with body: {"grant_type":"client_credentials","client_id":"...","client_secret":"..."}.
4. The response includes access_token, token_type":"Bearer", expires_in (default 1080 seconds — 18 minutes), and rest_instance_url.
5. Include the token as Authorization: Bearer ACCESS_TOKEN on all subsequent API requests.
Cache and reuse the token until near expiry; do not request a new token for every API call.
Triggered Sends: POST /messaging/v1/messageDefinitionSends/{definitionKey}/send — fires a triggered send to one or more subscribers. Body includes To.Address, To.SubscriberKey, and optional subscriberAttributes.
Contacts: POST /contacts/v1/contacts — creates or updates a contact. GET /contacts/v1/contacts/{contactKey} retrieves a contact.
Data Extensions (Async): POST /data/v1/async/dataextensions/{key}/rows — asynchronously upserts rows into a data extension. The async endpoint returns a request token; poll GET /data/v1/async/{requestToken} for status.
Data Extensions (Sync): POST /data/v1/customobjectdata/key/{key}/rowset — synchronous row insert for smaller payloads. Always prefer async for bulk operations.
The SOAP API uses the Enterprise WSDL at https://YOUR_SUBDOMAIN.soap.marketingcloudapis.com/etframework.wsdl. A RetrieveRequest message specifies:
ObjectType: The API object name (e.g., DataExtension, Subscriber, Send).
Properties: Array of field names to return.
Filter: A SimpleFilterPart with Property, SimpleOperator (equals, notEquals, isNotNull, greaterThan, etc.), and Value. Multiple conditions use ComplexFilterPart with LogicalOperator AND/OR.
The response uses MoreDataAvailable and RequestID for pagination — re-submit with ContinueRequest until MoreDataAvailable = false. WSProxy in SSJS wraps all this automatically.
Data views are system-managed tables queryable via SQL in Automation Studio Query Activities:
_Subscribers — all subscriber records and status.
_Sent — send event records (JobID, ListID, BatchID, SubscriberID, EventDate).
_Open — open tracking events (IsUnique).
_Click — click tracking events (URL, IsUnique).
_Bounce — bounce events (BounceType: SoftBounce/HardBounce).
_Unsubscribed — unsubscribe events.
_JourneyActivity — Journey Builder activity-level events.
Data views retain data for 6 months. Example: SELECT s.SubscriberKey, o.EventDate FROM _Sent s JOIN _Open o ON s.JobID = o.JobID AND s.SubscriberID = o.SubscriberID WHERE s.JobID = 12345.
In Automation Studio, a Query Activity uses SQL SELECT statements. The output DE must be specified in the Query Activity configuration — you cannot use SQL INSERT INTO syntax directly; Marketing Cloud routes the results to the target DE. Example:
SELECT
c.SubscriberKey,
c.EventDate AS ClickDate,
c.URL,
m.FirstName
FROM _Click c
JOIN MyMasterDE m ON c.SubscriberKey = m.SubscriberKey
WHERE c.IsUnique = 1
AND c.EventDate >= DATEADD(DAY, -7, GETDATE())

The target DE must have matching column names. Overwrite mode replaces all rows; Append mode adds rows. Query Activities have a 30-minute execution time limit.
CloudPages is Marketing Cloud's content hosting platform that publishes landing pages, microsites, and smart capture forms on a Salesforce-managed domain (or custom domain). CloudPages fully support AMPscript and SSJS, making them ideal for:
Dynamic landing pages: Personalise content based on URL query parameters or subscriber attributes passed from email links.
Preference centres: Read and update subscriber preferences in real time using AMPscript DE functions.
Smart Capture forms: Collect data and write directly to a DE via form submission (InsertDE or UpsertDE).
Redemption pages: Use ClaimRow to issue unique codes on page load.
AMPscript on CloudPages executes server-side at page request time, not send time, so RequestParameter("paramName") retrieves URL query string values.
The Journey Builder REST API allows external systems to inject contacts into a journey via an API Entry Event. Steps:
1. In Journey Builder, create an API Event entry source — this generates an EventDefinitionKey.
2. Define an Entry Source Data Extension with the fields you want to pass into the journey.
3. Publish the journey.
4. Call POST /interaction/v1/events with body: {"ContactKey":"sub123","EventDefinitionKey":"APIEvent-abc123","Data":{"FirstName":"Jane","Email":"jane@example.com"}}.
Marketing Cloud processes the event asynchronously and enters the contact at the journey's entry point. Unlike triggered sends, Journey API entries are rate-limited and best used for behavioural events (cart abandonment, form fill) rather than high-volume batch sends.
Triggered Sends use the legacy SOAP/REST triggered send definition and are associated with a triggered send DE; they have limited throughput and configuration flexibility.
Transactional Messaging API (TM API) is the modern replacement: POST /messaging/v1/email/messages/{messageKey}. Key differences:
— TM API has higher throughput (up to 2,500 emails/minute per MID on dedicated IPs).
— Supports synchronous send status response in near real time.
— Batch endpoint: POST /messaging/v1/email/messages/ accepts up to 50 recipients per batch call.
— Supports attributes and content.customerKey overrides per message.
— Requires a Transaction Definition Key created in Email Studio under Triggered Sends > Transactional Sends.
The Content Builder REST API uses the /asset/v1/content/assets endpoint:
Create: POST /asset/v1/content/assets with body containing name, assetType.id (e.g., 220 for HTML block), content (the HTML string), and optionally customerKey and category.id (folder).
Retrieve: GET /asset/v1/content/assets/{id} or search using GET /asset/v1/content/assets?$filter=name%20eq%20'MyBlock'.
Update: PATCH /asset/v1/content/assets/{id} with only the changed fields.
Delete: DELETE /asset/v1/content/assets/{id}.
Asset type IDs: 4 = webpage, 5 = webtemplate, 196 = template, 207 = HTML email, 220 = HTML content block, 230 = text content block.
PKCE (Proof Key for Code Exchange) is used when a public app (a client that cannot securely store a client_secret — e.g., a single-page app or mobile app) needs to authenticate against Marketing Cloud APIs.
Flow: The app generates a random code_verifier, hashes it to produce code_challenge, then initiates an authorization code flow with code_challenge_method=S256. After the user authenticates, the app receives an authorization code and exchanges it for tokens by sending the original code_verifier — the server validates the hash without ever receiving a client_secret.
In Marketing Cloud Installed Packages, choose Public App component type to enable PKCE. Server-to-Server components use client credentials flow (no PKCE needed). Web App components use standard authorization code flow with a client_secret stored server-side.
A Script Activity in Automation Studio runs SSJS server-side on a schedule or as part of an automation. Best practices:
Error handling: Wrap all logic in try { } catch(e) { } blocks. Log errors to a custom logging DE with fields: timestamp, scriptName, errorMessage, stackTrace.
Logging: Use Platform.Response.Write() sparingly (output is discarded in automation context); instead write log entries to a DE using Platform.Function.InsertDE() or WSProxy.
Idempotency: Check for existing records before inserting to avoid duplicate processing on retry.
Timeouts: Script Activities have a 30-minute limit. Break large batches into smaller automation runs or use Automation Studio loops with filtered DE segments.
Rate limits: Marketing Cloud APIs enforce rate limits (e.g., REST: 2,000 requests/minute). Implement back-off logic in SSJS using Platform.Function.Sleep(milliseconds).
Marketing Cloud enforces API rate limits per MID (business unit) to protect platform stability:
REST API: Generally 2,000 requests/minute. Some endpoints (e.g., contacts) have lower per-endpoint limits.
SOAP API: 2,000 requests/minute.
Transactional Messaging: Up to 2,500 emails/minute on dedicated IPs; shared IP limits are lower.
OAuth token requests: Throttled — cache tokens and reuse until near expiry (18 minutes).
Handling strategies: (1) Implement exponential back-off with retry on HTTP 429 responses. (2) Batch API calls where endpoints support it (e.g., TM API batch of 50). (3) Use the async data extension API for bulk DE operations rather than row-by-row REST calls. (4) Monitor rate limit headers (X-RateLimit-Remaining) in responses. (5) Distribute integrations across business units where architecture permits.

Ready to Practice with Mock Tests?

Reinforce your Marketing Cloud knowledge with our free practice exams.