I Tried Using GPT to Create a Custom Activity in Adobe Campaign Classic (And You’ll Be Surprised What Happened)
If you’ve ever worked with Adobe Campaign Classic (v7), you know the platform can be both incredibly powerful and incredibly complex. So when I needed to send WhatsApp messages from a workflow, my first thought was: surely this is going to take days of reading obscure documentation and trial and error. But then I thought – what if I just asked GPT to help?
Turns out, that was a bad idea.
What I Asked GPT to Build in Adobe Campaign Classic
Here were my requirements:
- The activity must be visible inside the ACC workflow.
- It should send one-way messages via the Meta WhatsApp Cloud API.
- It must support simple personalization (e.g., first name).
- All credentials and templates should be stored in Options.
- I didn’t want to handle replies or webhooks.
What GPT Gave Me: The Output Breakdown
And guess what? GPT delivered something that looked like total science fiction – and if you actually plugged it into Adobe Campaign Classic, it wouldn’t do anything. The problem is, there’s virtually no documentation available on the vast internet, and I’ve heard stories that GPT often returns incorrect or nonexistent syntax just to give some answer, instead of admitting, “Sorry, this is beyond my expertise.”
What Went Terribly Wrong with GPT Creating a Custom Activity
Basically, it pulled this from the AI realms on how Adobe Campaign Classic creates custom activities. Only thing it got right is that we have to extend xtk:workflow schema
<?xml version="1.0" encoding="UTF-8"?>
<schema namespace="cus" name="cus:whatsappActivity" extendsSchema="xtk:workflow">
<element name="activities">
<!-- Define a new custom workflow activity -->
<element name="whatsappSend" label="Send WhatsApp Message" category="Actions" icon="send.png">
<description>Sends a one-way WhatsApp message via Meta API</description>
<!-- One inbound transition, one outbound transition -->
<input cardinality="1" />
<output cardinality="1" name="success" defaultLabel="Sent messages"/>
<!-- (Optional) Define any custom UI parameters here if needed -->
<parameters>
<!-- (If we wanted user-configurable fields in the UI, define them here) -->
</parameters>
<!-- Reference the implementation script -->
<implementation language="javascript">whatsappSendScript</implementation>
</element>
</element>
</schema>
I was told, “Use Gemini — it will tackle this like it’s a piece of cake.” Gemini hallucinated even further beyond the AI realms. Maybe my instructions weren’t specific enough, but Gemini came up with this XML without even mentioning that I need to extend xtk:workflow.
<activity name="whatsappSender" img="nms:workflow.svg" label="Send WhatsApp Message" category="Interaction">
<input type="in" name="input" elementType="recipient" />
<parameters>
<param name="phoneField" type="string" desc="Field containing recipient's phone number" />
<param name="templateName" type="string" desc="Name of WhatsApp message template" />
<param name="personalizationField1" type="string" desc="Recipient data for personalization slot 1" />
<!-- Add more personalization fields as needed -->
</parameters>
<script>
<![CDATA[
// This is the JavaScript code executed by your custom activity
// (example using a conceptual direct approach, middleware is preferred)
function onExecute() {
// Get data from the workflow instance
var recipient = vars.source['input'].next();
if (!recipient) {
logWarning("No recipient found for WhatsApp activity.");
return;
}
var phoneNumber = recipient[@"$(phoneField)"]; // Accessing data from linked field
var template = vars.templateName;
var personalizationValue1 = recipient[@"$(personalizationField1)"];
// Retrieve credentials and template details from ACC Options
var accessToken = Xtk.server.GetOption("WhatsAppAccessToken");
var wabaId = Xtk.server.GetOption("WhatsAppBusinessAccountId");
var whatsappApiUrl = "https://graph.facebook.com/v19.0/" + wabaId + "/messages"; // Example API URL
// Construct your message payload based on Meta WhatsApp Cloud API documentation
var messagePayload = {
messaging_product: "whatsapp",
to: phoneNumber,
type: "template",
template: {
name: template,
language: {
code: "en_US" // Or dynamic based on recipient locale
},
components: [
{
type: "body",
parameters: [
{
type: "text",
text: personalizationValue1 // For personalization in the template body
}
]
}
]
}
};
try {
// This is a placeholder for HTTP POST request
// In reality, you'd use NLWS.HTTP or call your middleware
// NLWS.HTTP.Post(whatsappApiUrl, JSON.stringify(messagePayload), {'Authorization': 'Bearer ' + accessToken, 'Content-Type': 'application/json'});
logInfo("Attempting to send WhatsApp message to " + phoneNumber + " using template " + template);
// --- REPLACE THIS WITH ACTUAL HTTP CALL OR MIDDLEWARE CALL ---
// Example with a conceptual Middleware endpoint:
// var middlewareUrl = "https://your-middleware.com/send-whatsapp";
// var middlewarePayload = {
// phoneNumber: phoneNumber,
// templateName: template,
// personalization: {
// 'first_name': personalizationValue1
// }
// };
// NLWS.HTTP.Post(middlewareUrl, JSON.stringify(middlewarePayload), {'Content-Type': 'application/json'});
// --- END REPLACE ---
logInfo("WhatsApp message successfully initiated for " + phoneNumber);
} catch (e) {
logError("Failed to send WhatsApp message to " + phoneNumber + ": " + e.message);
// Optionally, handle retry or error propagation
}
}
]]>
</script>
</activity>
What Went Tremendously Wrong with GPT Creating a Custom Activity
GPT is very capable of programming – there is no doubt about that – and it can definitely handle tasks for me when it comes to technologies with vast resources available on the internet (it’s helped me and saved a lot of time building features on the blog). But again, that’s not how Adobe Campaign Classic works. This niche requires experience to navigate all the struggles – mostly alone or occasionally with a little help from the online world.
The only few things that’s correct is the use of getOption() and the HTTPS request JSAPI function. But traversing recipients from vars.recipient is something that compromises the entire code right at line number 17.
// Get global option values
var apiUrl = getOption("WhatsApp_API_Url"), // e.g. "https://graph.facebook.com/v17.0/1234567890/messages"
apiToken = getOption("WhatsApp_API_Token"), // Bearer token for auth
senderId = getOption("WhatsApp_Sender_Phone_ID"),// Your WhatsApp Business phone number ID
templateName = getOption("WhatsApp_Template_Name"), // Template name (if using template messages)
templateLang = getOption("WhatsApp_Template_Language"), // Template language code (e.g. "en_US")
defaultMsg = getOption("WhatsApp_Default_Template"); // Default message template text
// Prepare HTTP client for WhatsApp API
var request = new HttpClientRequest(apiUrl);
request.method = "POST";
request.header["Content-Type"] = "application/json";
request.header["Authorization"] = "Bearer " + apiToken;
// Iterate over inbound records (profiles) from the transition
var recipientCount = 0;
for each (var profile in vars.recipient) {
recipientCount++;
// Example assumes 'vars.recipient' is the collection of inbound profiles.
// If not directly available, you might query the temporary table using queryDef.
// Personalize the message content:
var firstName = profile.firstName; // assuming schema has firstName
var personalizedText = defaultMsg.replace("{firstName}", firstName || "")
.replace("{lastName}", profile.lastName || "");
// (Add more replacements as needed for other placeholders)
// Construct request payload for WhatsApp API
var payload = {
messaging_product: "whatsapp",
to: profile.mobile, // assuming 'mobile' contains the phone number (including country code)
type: "text",
text: { body: personalizedText }
};
// If using a template message instead of free-form text (outside 24h session):
// payload = {
// messaging_product: "whatsapp",
// to: profile.mobile,
// type: "template",
// template: {
// name: templateName,
// language: { code: templateLang },
// components: [{
// type: "body",
// parameters: [
// { type: "text", text: firstName || "" },
// /* add other parameters if template expects them */
// ]
// }]
// }
// };
request.body = JSON.stringify(payload);
try {
request.execute(); // send the HTTP request
var resp = request.response;
if (resp.code != 200 && resp.code != 201) {
logError("WhatsApp API error for profile " + profile.id + ": HTTP " + resp.code + " - " + resp.body);
} else {
logInfo("WhatsApp message sent to " + profile.mobile + " (Profile ID " + profile.id + ")");
}
} catch(e) {
logError("Exception sending WhatsApp message for profile " + profile.id + ": " + e.message);
}
}
What I have expected to get from GPT
I get why this is a huge miss for AI — Adobe Campaign Classic is a niche platform with basically only one resource on the internet explaining how to create a custom activity. When you build a custom activity, you need to modify several files. First, you have to extend the workflow schema, define the name and library. Then, you need to amend the workflow form for your custom activity and implement the corresponding JavaScript library defined in schema.
In conclusion, GPT is a powerful tool when it comes to general-purpose or well-documented technologies. It can speed up development, offer reliable guidance, and even help build complex features with ease. But when it comes to niche platforms like Adobe Campaign Classic, things get tricky. The lack of comprehensive technical documentation means GPT often has to guess or fill in gaps, which leads to inaccurate or unusable results. Until this kind of specialized knowledge becomes more available online or GPT gets trained on more in-depth internal documentation, it will take time and manual correction to produce truly relevant outcomes in these areas.






