Hi,
So there is an upcoming tradeshow and we are giving out free passes to people who submit the form.
There are a limited number of passes, and the pass codes have been provided to us.
I am searching for a way to automatically send out these confirmation emails with the unique codes embedded in the emails.
I also need to know when we have exhausted the codes that we have.
I tried looking on the Nation, but didn't see a solution.
Thanks,
Stephen
Solved! Go to Solution.
- Create a custom text {{my.passcode}} token local to your program (add a placeholder default value as the token value)
- ...
This is a little development heavy method and you'll definitely need a technical person to pull this off. I'll let Sandy confirm if there's a comparatively less dev heavy/easier solution to pull this off! 🙂 Thank you.
Hm. That sounds far too complex. You need to keep a pointer to the most recent code on the stack, which means a separate database. And you need a separate web app to call the REST API!
You want to avoid both REST API calls and any (trivially hackable) calls made from the form. All logic should be initiated on the Marketo server side.
The better way to do this is via a webhook-compatible service. It shares some of the general logic above. But you can store the codes in a simple text file in Design Studio. Then each time the webhook is called, you increment the pointer by 1 and get the Nth line in the file. Return that in the webhook: done.
I’ve done this a bunch of times and if you search my past posts you’ll get some pointers. It’s like < 10 lines of code.
Easier still is to “reverse the charges”: have Marketo generate the unique code, then call an external service to say “Hey, I assigned such-and-such code to the lead with this email address.” You can generate an acceptably unique code by mixing together the person’s Marketo Unique Code with the Program ID. The end user will not be able to guess this.
if you must use pre-determined codes, then go with @SanfordWhiteman's approach. A great option for the webhook compatible service he's talking about is flowboost. Sanford didn't mention it as he wrote it.
cheers
Jo
Off the top of my head, here's what you can do -
This is a little development heavy method and you'll definitely need a technical person to pull this off. I'll let Sandy confirm if there's a comparatively less dev heavy/easier solution to pull this off! 🙂 Thank you.
- Create a custom text {{my.passcode}} token local to your program (add a placeholder default value as the token value)
- ...
This is a little development heavy method and you'll definitely need a technical person to pull this off. I'll let Sandy confirm if there's a comparatively less dev heavy/easier solution to pull this off! 🙂 Thank you.
Hm. That sounds far too complex. You need to keep a pointer to the most recent code on the stack, which means a separate database. And you need a separate web app to call the REST API!
You want to avoid both REST API calls and any (trivially hackable) calls made from the form. All logic should be initiated on the Marketo server side.
The better way to do this is via a webhook-compatible service. It shares some of the general logic above. But you can store the codes in a simple text file in Design Studio. Then each time the webhook is called, you increment the pointer by 1 and get the Nth line in the file. Return that in the webhook: done.
I’ve done this a bunch of times and if you search my past posts you’ll get some pointers. It’s like < 10 lines of code.
Easier still is to “reverse the charges”: have Marketo generate the unique code, then call an external service to say “Hey, I assigned such-and-such code to the lead with this email address.” You can generate an acceptably unique code by mixing together the person’s Marketo Unique Code with the Program ID. The end user will not be able to guess this.
if you must use pre-determined codes, then go with @SanfordWhiteman's approach. A great option for the webhook compatible service he's talking about is flowboost. Sanford didn't mention it as he wrote it.
cheers
Jo
Indeed! The FlowBoost webhook payload would be like:
var fileOfCodes = "https://pages.example.com/rs/111-222-333/images/sample_codes.txt";
var counter = "/distributed_codes/{{Program.Id}}/v1";
FBHttp.fetch(fileOfCodes)
.then( resp => resp.text() )
.then( respT => respT.split(/\r?\n/) )
.then( codes =>
FBCounter.count(counter)
.catch( count => 0 )
.then( count =>
count < codes.length
? FBCounter.autoAdd(counter).then( resp => success(codes[count]))
: failure("All outta codes!")
)
)
.catch(failure)
Where sample_codes.txt is a simple text file in your Design Studio with one code per line:
QNFTMGPXLKC2
L09J6I8BTLJF
SQ5L263BDN23
AHDX8LZD91NT
UTWMHM7GFRTV
Then the webhook will return one code at a time like
{
"response": "QNFTMGPXLKC2"
}
{
"response": "L09J6I8BTLJF"
}
until it runs out.
I’ve also been working on a recipe for a very streamlined webhook-compatible service that you can spin up in seconds on AWS. It does 2 things, and 2 things only:
With those 2 simple features you can achieve some really complex stuff.
Let’s say you have a file codes.json in your Design Studio:
[
"QNFTMGPXLKC2",
"L09J6I8BTLJF",
"SQ5L263BDN23",
"AHDX8LZD91NT",
"UTWMHM7GFRTV"
]
Then your webhook URL could be like:
https://hookones.teknkl.com/?file=codes.json&counter=counter1
And the webhook payload is just the one-liner:
$.[${counter}]
The variable ${counter} gets replaced by the counter value, so each time you call it the JSONPath changes:
$.[0]
$.[1]
$.[2]
thereby fetching a new code off the stack.
Hi SanfordWhiteman,
My name is Jeff and I'm assisting my colleague Steve with this task. I'm a web developer but have zero experience with Marketo and using these built in web hooks.
Do you know of a resource that I can reference, other than this Marketo Nation forum community, that shows step by step, how to build this webhook and connect it to the Marketo workflow? This is my understanding of the process so far:
1) User fills out the form and submits
2) Marketo replies with an email confirming their submission
a) during the creation of the email, we call the webhook and retrieve the pass code via : "response": "QNFTMGPXLKC2"
b) if we have a value, we place the value of the response in a token (a placeholder??) or
if the webhook returns no value (there are no more codes), we may let the customer know that we have exhausted all pass codes (codes)
3) In your sample webhook code (1st one) , you have two lines at the top
var fileOfCodes = "https://pages.example.com/rs/111-222-333/images/sample_codes.txt";
var counter = "/distributed_codes/{{Program.Id}}/v1";
fileOfCodes is a variable holding the text file, we import that file into marketo and adjust the https://pages.example.... with the actual path where we uploaded the text file
counter is a variable holding the count. What does or how does the "/distributed_codes/{{Program.Id}}/v1" keep track of the count?
When creating the webhook, where do we put the sample code?
var fileOfCodes = "https://pages.example.com/rs/111-222-333/images/sample_codes.txt";
var counter = "/distributed_codes/{{Program.Id}}/v1";
FBHttp.fetch(fileOfCodes)
.then( resp => resp.text() )
.then( respT => respT.split(/\r?\n/) )
.then ( codes =>
FBCounter.count(counter)
.catch( count => 0 )
.then( count =>
count < codes.length
? FBCounter.autoAdd(counter).then( resp => success(codes[count]))
: failure("All outta codes!")
)
)
.catch(failure)
What I really would like to see is how to create a webhook step by step and how to integrate the new webhook in the workflow process.
Thanks so much for your help.
Jeff
When creating the webhook, where do we put the sample code?var fileOfCodes = "https://pages.example.com/rs/111-222-333/images/sample_codes.txt"; var counter = "/distributed_codes/{{Program.Id}}/v1"; FBHttp.fetch(fileOfCodes) .then( resp => resp.text() ) .then( respT => respT.split(/\r?\n/) ) .then ( codes => FBCounter.count(counter) .catch( count => 0 ) .then( count => count < codes.length ? FBCounter.autoAdd(counter).then( resp => success(codes[count])) : failure("All outta codes!") ) ) .catch(failure)
That goes in the webhook Payload textbox.
But I think there’s one piece you might not be clear on: you need a FlowBoost API key to make this call. It’s free (Community key is 100,000 calls/month which certainly seems beyond your usage) but you need to fill out the form!
Hi Sanford!
Thanks a lot, this function is exactly what I'm looking for. I've set everything up through FlowBoost, although I always receive the below response message:
{"errorType":"string","errorMessage":"ERR: Compile error (strict mode): SyntaxError: Invalid regular expression: missing /","trace":[]}
Any idea what might cause this and how should I fix it?
The code you've provided is unchanged basically other than the fileOfCodes path of course.
--
I ruled out the possibility that I've set up FlowBoost poorly, as the much simpler "Hello World!" call went through beautifully with the same setup.
If you need any other details, let me know. Thanks a lot!
It’s tricky because in the webhook UI you have to double up those escapes in order for Marketo to send the right thing on the wire. Otherwise Marketo swallows them. Try:
.then( respT => respT.split(/\\r?\\n/) )
Yeah, it works fine now! Thanks Sanford!
I have another concern though, one that might never happen actually but I can not rule out the possibility.
So, when I run the webhook on a sample of 60 records (with 45 codes only), many of them receive back the same code. Only 24 get unique codes in the end, but more importantly, none gets back "nothing" as the value of 15 should because we have fewer codes than people qualified.
I realize if my trigger would be closer to a realistic one like "fill out a form" then the possibility of this is closer to 0, as people won't be entering the flow in one batch, but wondering if 2 form submissions are really really close in time, would that result in the same situation described above? Trying it with a smaller sample of 5, adding a 1-second delay between each record's webhook call seems to solve the issue, but it's not scalable. The question in the end is if the payload can be adjusted to have some sort of delay that solves this issue or if the delay should happen in the smart campaign flow. And more importantly, if I'm overthinking it in the first place?:D
Thanks a lot!
You’re right that because of multithreading (or, more precisely, multi-processing) on the FlowBoost side that code could return duplicates under high parallel load.
You can avoid that by changing the order of operations, so everyone gets a unique counter index before looking up that index (i.e. row) in the file w/values:
var fileOfCodes = "https://pages.example.com/rs/111-222-333/images/sample_codes.txt";
var counter = "/distributed_codes/{{Program.Id}}/v4";
Promise.all([
FBHttp.fetch(fileOfCodes).then(resp => resp.text()),
FBCounter.autoAdd(counter)
])
.then( ([fileContents, counters]) => {
let codes = fileContents.split(/\r?\n/);
let nextCode = codes[counters.currentCount - 1];
if(nextCode) {
success(nextCode);
} else {
failure("All outta codes");
}
});
I think the issue still stands. Now running this code on a smaller sample of 20 (still at the same time) continues to return duplicates and one more empty value than it should. Sample: 20 codes, 21 records.
Result below:
Email Address | Last Unique Code |
1 | |
2 | Code6 |
3 | Code18 |
4 | Code18 |
5 | Code17 |
6 | Code5 |
7 | Code12 |
8 | Code11 |
9 | Code10 |
10 | Code11 |
11 | Code2 |
12 | Code3 |
13 | Code17 |
14 | Code2 |
15 | |
16 | Code10 |
17 | Code17 |
18 | Code19 |
19 | Code5 |
20 | Code17 |
21 | Code10 |
Sorry, one important change I forgot to recommend!
Use
let nextCode = codes[counters.entryIndex];
instead of
let nextCode = codes[counters.currentCount - 1];
The 2 differ significantly. entryIndex is the index of the just added entry in the list, which is what you actually want here. currentCount is the size of the whole list, which at certain points in time (under load) may include entries who were added milliseconds after the current person — that’s why currentCount can end up assigning a code that shouldn’t be given out to this specific person, but to someone else.
At any rate, use entryIndex. I tested multiple times with a 50-code file and 50-person list and everything was correct.
Now it's perfect, thank you!
The explanation helps a lot as well!
Excellent! This needs better/some documentation. 🙂
OK, I’m back with more answers! Had a call.
3) In your sample webhook code (1st one) , you have two lines at the topvar fileOfCodes = "https://pages.example.com/rs/111-222-333/images/sample_codes.txt"; var counter = "/distributed_codes/{{Program.Id}}/v1";
fileOfCodes is a variable holding the text file, we import that file into marketo and adjust the https://pages.example.... with the actual path where we uploaded the text file
counter is a variable holding the count. What does or how does the "/distributed_codes/{{Program.Id}}/v1" keep track of the count?
Yes, fileOfCodes points to the Design Studio asset.
The code is using FBCounter (actually a simple key-value database, etcd, under the hood) and its method called autoAdd(). autoAdd() just adds an automatically-generated unique entry (like a GUID) under the counter path (/codes/12345/v1/...) every time you call it. So it doesn’t have to know what it’s counting — it just counts and tells you how many entries there are!
Hi Jeff,
I’ll answer in a few parts for readability.
2) Marketo replies with an email confirming their submission
a) during the creation of the email, we call the webhook and retrieve the pass code via : "response": "QNFTMGPXLKC2"
b) if we have a value, we place the value of the response in a token (a placeholder??) or
Wouldn’t exactly say “during creation” of the email here as you’d call the webhook in response to the form fill.
In the webhook Response Mappings, you’d set the Response Attribute (left-hand-side) to response and the Marketo Field (right-hand-side) to a new custom String field you create for this purpose.
That Last_Passcode field will automatically be available as the token {{lead.Last Passcode}} in emails.
if the webhook returns no value (there are no more codes), we may let the customer know that we have exhausted all pass codes (codes)
Yes, you can detect the error message “All outta codes!” in a couple of different ways:
1. Map the Response Attribute errorMessage to another Marketo Field like Last Passcode Fetch Error or similar, and watch for changes to that field.
2. Trigger on the Webhook is Called activity with the response containing “All outta codes!”.
I am searching for a way to automatically send out these confirmation emails with the unique codes embedded in the emails.
To be clear, you have a stack of unique codes (not preassigned) and you want to pull a new code off the stack whenever somebody submits the form, assigning it to that lead?
To be clear, you have a stack of unique codes (not preassigned) and you want to pull a new code off the stack whenever somebody submits the form, assigning it to that lead?
Yes, that is correct.
I have a list of codes and need to assign them when the form is submitted.