Skip navigation
All Places > Products > Blog
1 2 3 Previous Next

Products

321 posts

Can't believe someone other than me has thought about cryptographic techniques in Marketo! But in this recent Nation thread, a user asked about attaching the SHA-256 hash of a recipient's email address to (email) links.

The aim being to send a secure representation of a lead's email to an external (non-Marketo) site, where it could be looked up as part of a 3rd-party subscription center.

In other words, a link would look like this:

http://nonmarketopage.example.com/?emailHash=284C36B4333F55511617FB225C62813316038522DF5C2AEC6B6B13B3D3774F5C

The target site's database would hold pre-computed hashes of all their registered users' emails, the hash being stored in a separate column from the email itself.[1]

A match would then be done from hash-to-hash (the way hashes are always used, since they can never be reversed to the original input) to load the user's record.

Mind you, I have no idea why this would actually be done as opposed to sending the URL-encoded email address:

http://nonmarketopage.example.com/?email=sandy%40figureone.com

Or the easily reversed, Base64-encoded (not encrypted) address, which wouldn't require a hash lookup:

http://nonmarketopage.example.com/?emailB64=c2FuZHlAZmlndXJlb25lLmNvbQ==

Being a realist, I suspect the justification is merely that they want the links to look more “technical” than they would with Base64 (?) and they don't truly have any need for security (as it makes little sense to care about the security of the recipient's own email address![2]). UPDATE: OP says the client now wants AES encryption instead of hashing, so they really are trying to securely transport stuff in the URL. That gives me a chance to bring out the big guns and show you how encryption is done in VTL... at some point.

Anyway, should you need it, here's a utility Velocimacro to gen a SHA-256 hash:

#**
    HashTool in VTL v2
    @copyright (c) 2018 Sanford Whiteman, FigureOne, Inc.
    @license MIT License: all reproductions of this software must include the data above
*#
#macro( SHA256_v2 $mktoField )
## reflect some dependencies
#set( $Class = $context.getClass() )
#set( $java = {} )
#set( $java.lang = {
     "StringBuilder" : $Class.forName("java.lang.StringBuilder"),
     "Appendable" : $Class.forName("java.lang.Appendable")
} )
#set( $java.security = {
    "MessageDigest" : $Class.forName("java.security.MessageDigest")
} )
#set( $java.util = {
    "Formatter" : $Class.forName("java.util.Formatter").getConstructor($java.lang.Appendable)
} )
## get an MD and make it go, then (important) reset MD singleton for reuse
#set( $MD = $java.security.MessageDigest.getInstance("SHA-256") )
#set( $digestBytes = $MD.digest( $mktoField.getBytes("utf8")) )
#set( $void = $MD.reset() )
## gen hex string representation
#set( $hexString = $java.lang.StringBuilder.newInstance() )
#set( $hexer = $java.util.Formatter.newInstance($hexString) )
#foreach( $B in $digestBytes )
#set( $void = $hexer.format("%02x",$B) )
#end
## return uppercase, but note a hex string should be treated as case-insensitive
$hexString.toString().toUpperCase()##
#end

After including the above in its own token (best to not pollute your user code with utility functions) use the macro like so:

#set( $emailHash = "#SHA256_v2($lead.Email.toLowerCase())" )
<a href="http://www.example.com/?emailHash=${emailHash}">Click here</a>

Note that I toLowerCase()d the Email before passing it, as that's appropriate for that particular field (as I've written about before, though SMTP addresses are actually case-sensitive, they're commonly matched case-insensitively for sanity's sake).


NOTES

[1] Hope I'm not hoping for too much here. They'd better be already pre-computing hashes for all the stuff in their database, or this idea goes from merely frivolous to very bad. If they didn't pre-hash, they'd have to hash every record in the database, on-the-fly, for every lookup. This would absolutely destroy performance and be a sign that the back end was not well thought out.

[2] Long as the destination site runs SSL. But if the site doesn't run SSL then the connection could be intercepted and you have a lot worse problems than showing the attacker an email address.

The Forms 2.0 Email type — just like a standard HTML <input type="email"> — won't throw an error on email addresses like:

 

sandy@gmail

jeff@amazon

alejandra@zz

That is, domains with only a single DNS label to the right of the @ sign (@example), rather than multiple labels separated by dots (@example.com or @example.co.uk), are valid entries.

Confusing, sure. But no, it's not a bug. A mailbox @ a single-label domain isn't an “incomplete” or “partial” address, and while most such addresses happen to be invalid on the public internet, it's impossible to know whether they're valid using JavaScript alone.

To understand why, you have to know more about how SMTP domains are looked up in the global DNS.[1] (To my admittedly unreasonable dismay, nothing about SMTP or DNS is taught to marketing students!)

A laughably brief overview of SMTP and DNS

This is silly to try to go over quickly. But here are the basics:

  1. (1) For an email address to be theoretically routable over the public net, it must have a domain part, the part to the right of the @.
  2. (2) For an email address to be factually routable over the public net, the domain needs to have an MX record[2] in the global (public) DNS.
  3. (3) A web browser cannot perform arbitrary DNS lookups on its own, so it cannot know whether a domain actually exists, let alone what records are in the DNS zone. It can only know if it's well-formed: that is, if it matches the string syntax rules for a domain.
  4. (4) A single-label domain like gmail (or, for that matter, a single label like com) is no less a well-formed domain than one with multiple labels, like gmail.com or zyzzx.co.ukOnce looked up, these will differ greatly in terms of being private (assigned year-by-year to a company or other entity) or public (registered semi-permanently to a country or independent NIC operator).[3] And they may or may not be registered, or even legally eligible for registration, at a given point in time. But they are nevertheless all domains.
  5. (5) A single-label domain, if it exists in the global DNS, may also have an MX record (and some, as we shall see, do). It's a rare case, yes — but it's technically valid, and since form inputs don't perform DNS lookups, there's no way to know whether the particular single-label domain somebody entered is routable or is a dead end.

In sum, the only thing a web browser alone can know about a domain, without invoking a remote lookup service, is that it follows proper syntax. It can't have commas instead of dots; it can't have anything other than a tiny subset of ASCII characters (though it may be displayed as if it has more exotic characters, which is another topic); it can't have an individual label longer than 63 characters; it can't have 2 dots in a row; the total length including dots can't exceed 253. That's pretty much it: one string that matches those requirements is as valid as any other.

You might be getting it already, but let's go further

From the intro above, you should already have your mind opened.

But what exactly do I mean when I say a single-label domain may still be a publicly routable domain? Most likely, you've never sent or received mail from joe@gmail, only joe@gmail.com. But that's just because you haven't sent enough email. (Like, you haven't personally sent billions of messages!)

As of today, these TLDs have MX records, meaning the email address user@tld is publicly routable:

.ai .ax .cf .dm .gp .gt .hr .km .lk .mq .pa .sr .tt .ua .ws

These are mostly small island countries, like Anguilla, Dominica, and Trinidad and Tobago. With full respect to the governments of those countries, with relatively limited budgets they may have set the records up accidentally. But the list also includes Guatemala (.gt), Ukraine (.ua) and Sri Lanka (.lk) — so we must assume it's no accident that you can address mail to sirisena@lk.

I get that you still want to “fix” your forms, though

Even if you believe everything above, you probably still want to hand-wave it and require multi-label domains! So here's a little snippet if you insist:

 

MktoForms2.whenReady(function(form) {   
  form.onValidate(function(nativeValid) {      
    if (!nativeValid) return;      
    var currentValues = form.getValues(),         
    formEl = form.getFormElem()[0],         
    emailEl = formEl.querySelector("[name=Email]"),         
    RE_EMAIL_ASCII_PUBLIC = /^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+$/;      

    form.submittable(false);      
    if (!RE_EMAIL_ASCII_PUBLIC.test(currentValues.Email)) {         
      form.showErrorMessage(            
        "Must be valid email. <span class='mktoErrorDetail'>user@example.com</span>", 
        MktoForms2.$(emailEl) 
      );      
    } else {         
      form.submittable(true);      
    }   
  });
});

Obviously if you already have custom onValidate behaviors, you have to integrate this code with those. (When you're flipping the Forms 2.0 global submittable flag on and off, you need to make sure all conditions are considered together.)

A deep note about commercial gTLDs

OK, there is one glitch in my claim that browsers are completely justified in accepting all single-label domains in Email inputs.

In fact, newfangled domains like .space and .lawyer and .futbol are expressly prohibited from having MX records at the top level. From the guidebook for applying to run one of these “new gTLDs”:

ICANN receives a number of inquiries about use of various record types in a registry zone, as entities contemplate different business and technical models. Permissible zone contents for a TLD zone are:

• Apex SOA record.

• Apex NS records and in-bailiwick glue for the TLD’s DNS servers.

• NS records and in-bailiwick glue for DNS servers of registered names in the TLD.

• DS records for registered names in the TLD.

• Records associated with signing the TLD zone (i.e., RRSIG, DNSKEY, NSEC, and NSEC3).

In other words, non-essential records like A or MX records are not permitted at the apex level of these new gTLDs.

The guide does go on to imply that another record type might be permitted by special exception, but it seems awfully doubtful that any would ever be approved:

An applicant wishing to place any other record types into its TLD zone should describe in detail its proposal in the registry services section of the application. This will be evaluated and could result in an extended evaluation to determine whether the service would create a risk of a meaningful adverse impact on security or stability of the DNS.

So, if you know you're dealing with one of these new gTLDs, .lawyer for example, you in fact can be sure without a DNS lookup that joe@lawyer will not be routable over the net, since that top-level domain is not legally allowed to accept mail.

So browsers could, in theory, throw an error on <user@new gTLD> (since they do have a copy of the Public Suffix List internally and don't have to hit DNS for that). But, well, they don't. Go figure!


NOTES

[1] Plus, it helps to understand that SMTP delivery doesn't even require a DNS lookup. The SMTP standard predated DNS by a few years, and even today billions of messages are passed from server to server without DNS being consulted. But I'm going to ignore this other contributing factor today.

[2] Yes, for the purists, an MX or an A record. I'm not trying to overwhelm people here.

[3] Or of course the 3rd variant: private on the pure DNS level, as they're children of a public TLD, but to be treated as public for purposes of browser security. This is why the PSL exists: it tracks the effective public domains, a list which can't be derived via DNS alone.

By Phillip Wild, original discussion can be found here.

 

Marketo’s Engagement Programs can do some extremely useful things for the marketer. What was once a series of complicated user journeys can now be distilled into an email drip campaign (called “casts”) based on a cadence you specify.

However, the built-in functionality has one flaw for how we run things at G Adventures:

 

If you use sub-programs, and a person doesn’t get sent the email via a smart campaign when the cast goes out, the system will stop there and won’t check the next program.

 

Effectively, when a person enters a sub-program within an engagement program, and triggers a smart campaign, regardless of whether they qualify or not, Marketo will stop. It won't check the next one. Great behaviour in some cases, but not for what we are trying to do at our business.

 

Let’s illustrate this with an example. Let’s say we have the following structure in an engagement program.

 

 

You can see that we have three streams — based on the time zone of the sends — that are otherwise identical. Within the streams, we have a series of 8 emails.

 

This structure is designed to give a person in this program one email a week on a Tuesday. It’s a group of our most engaged leads, so we are trying to send them the most appropriate content in order to get them to make that last step and book a tour. Each of these emails has an additional set of criteria beyond simply being a member of the engagement program (we don’t want to send our Active tour content to those who habitually book our polar expeditions, for example). So whenever the engagement program “casts” out a send, the default behaviour is:

 

  1. Check membership of the top program (basically, whether they have received the email previously). If a member, then start this process again, but from the next program down.
  2. If not a member, then check criteria for the send. If criteria passes, send the email. If it doesn’t pass, do nothing.

So that’s great if the user has already received the first email (defined in Marketo-speak as “is a member of the first program”). But if they haven’t, and they don’t qualify for the send, then…and this is the important bit…Marketo won’t check whether they qualify for the next program immediately, but will instead do nothing for that cast and will wait until the next occurrence. So in our situations of 8 programs above, top to bottom, each with narrowly defined criteria, then with a weekly cadence of sends:

  1. If you qualify for emails 1,6 and 7, you would receive an email the first week, nothing for 5 weeks, then emails 6 and 7, finishing with nothing in the last week.
  2. If you qualify for emails 2,3 and 4, you would receive nothing the first week, then an email a week for the next three weeks, then nothing for the remaining 4 weeks.

This clearly isn’t great for what we are trying to do here. We are trying to motivate this highly interested group of people to book, so for them to go several weeks without receiving what would be a highly effective piece of communication is very sub-optimal.


So how can we get around this? One way would be to use emails instead of sub-programs in the engagement program above — but you can’t have additional criteria on an email cast. The email would go out to everyone. That’s not going to work given how targeted these communications are. Not an option. The solution is to use how Marketo defines membership to “skip” non-qualifying emails. (A shout out to Roxanne McGlumphy at Marketo first off for showing us this little-known hack. It’s been incredibly useful for us).You might have noticed from the explanation above that Marketo first checks for “membership” of a sub-program before it even looks into the criteria for sending. If a person is already a “member”, Marketo decides that it must have already received that send, and moves on to the next one — immediately! So if you set membership of a program for those that you DON’T want to receive it, Marketo will skip them through to the next program, and so on until it finds something they are not a member of, or until we run out of content.


To build this in practice, here’s what we did and the thought process behind it:

  • Our deployments trigger from around 2:00am — 6:00pm EST Tuesdays. So membership of sub-programs would need to change before then.
  • We also need to change membership back for those who didn’t end up receiving the email. Otherwise, if they stay as a member of the sub-program forever, they will never be able to receive the send, regardless of whether they qualify or not.

Extrapolating upon this, let’s say our criteria for the first sub-program, “Non Inca Trail Peru”, is something like this. You will receive it if:

  • You’re an email subscriber; AND
  • You’ve never received that email before; AND
  • You are interested in Peru.

So if we want to ensure that those that shouldn’t receive it will be “skipped”, and could potentially receive the next email immediately, then we need a smart campaign to run each Monday night with the following criteria:

  • You’re not an email subscriber; OR
  • You’ve received that email before; OR
  • You’re not interested in Peru.

For anyone who qualifies for that smart campaign, you want to use this flow step: By changing their Program Status of the sub-program to be “Sent” you are making them a member of that program, and ensuring they will be skipped in the next cast. Marketo thinks they have already received it.That program should run weekly, just before your cast goes out. If your casts only occur monthly, then you would only run that smart campaign monthly (you get the idea). Now the second element: for those who didn’t receive the email, change their status back to not be a member of that program. It’s entirely possible that after you changed them to be a member they became interested in Peru, became an email subscriber, or both! So they should qualify for that send next time. This smart campaign will run after all your casts have completed (in our case, after 6pm Tuesday EST), and will have the criteria: Pretty straightforward. Since an email could live in multiple engagement programs, we use “contains” instead of the absolute match of “is” (Marketo believes that an email in a different program is a different email). And the flow step: So each week, here is what is happening:

  1. Before the first cast on Tuesday at 2am EST, we are checking membership for all sub-programs in the engagement program, and marking those who don’t qualify as “members” of those programs.
  2. Marketo runs through the casts and will move straight on to the next sub-program if it finds that a person is a member. So if you only qualify for emails 4 and 5, you will receive email 4 in the first week, and email 5 in the second week. Receiving the email will change a person’s membership of a sub-program to “member”.
  3. Once the casts are done, for anyone who is a member of the sub-program but didn’t receive the email, change them back to not be members of those programs, so they can qualify for future sends.

The power of this should be apparent. You no longer have to settle for one of two options:

  1. Having a generic stream of content where everyone receives ALL emails in the stream, sequentially.
  2. Having a customised stream where you can qualify for one, some, or all, but you have to wait for several casts before receiving the piece you actually qualify for.

This method allows you to build a dynamic queue of content that will be different for each user. And don’t forget, within Marketo engagement streams you can also:

  • Have “timed” content so it only goes out during a certain time period;
  • Change the order of content in the stream to prioritise based on objectives;
  • Use email scripting and/or dynamic content to customise your emails further;
  • Send more than emails — flow steps are available to you as part of sub-programs, so think sales alerts, remarketing lists for social, or even webhooks for direct mail sends.

 

It’s a bit daunting at first, but once you see the power of engagement programs used in this manner, it’s going to be hard to argue with the results. Happy casting!

By Tom Grubb, Chief Strategy Officer, Digital Pi

 

What can you say about marketing analytics that hasn’t already been said? Plenty when you know how many well-intentioned marketers too often misrepresent, misread, misunderstand, miscalculate and flat-out misuse – or don’t use marketing analytics at all. Considering the amount of time and money companies invest in people, technology and marketing programs one would think that getting marketing analytics right and putting them to work to improve ROI would be a top priority for every organization right up to the CEO. Even the companies that make marketing analytics a top priority often fail to set the right objectives, ask the right questions, and drive adoption across business functions. The journey to transforming your organization to embrace marketing analytics as the common language of marketing isn’t a journey at all: it’s a mission that requires a leader who’s not afraid to take on this formidable challenge.

Revenue_Attribution_Post_Quote_1.pngIn my work consulting with Marketo customers I’ve seen how marketing analytics champions can become a lightning rod for criticism from all sides for many reasons. The area of analytics that causes the most problems for those championing analytics is revenue attribution reporting – the method of tying marketing performance to revenue in order to use pipeline and revenue as a guide for optimizing marketing. In plain speak, the question can be framed as “show me which programs or tactics had the most/least influence on pipeline created or revenue won.” The good news for Marketo customers is this: the Marketo platform is designed to collect and manage data in a way that lends itself to revenue attribution reporting. Before I dive into Marketo’s revenue attribution model, we need to consider a very different approach to revenue attribution that I encounter in various forms: single source revenue attribution.

 

For this article, I am focusing on B2B companies. Single source attribution says, we can attribute the entire credit for an opportunity to one buyer – say, Sarah Smith, the Director of Purchasing. If lead source is the one and only attribution we apply, and we say Sarah is the person in the deal who counts the most, then we look at Sarah’s lead source – trade show, and apportion all of the credit for revenue to the trade show that acquired Sarah’s name in our database – great job marketing! Or alternatively, assume instead a sales person found Sarah on LinkedIn and added her name to the database. In that case, all of the credit for the deal would go to Sales for finding Sarah. There are lots of ways to declare single-source credit for a deal, from acquisition program to last response, to home-grown algorithms. The overarching goal for single source attribution is usually to determine whether sales or marketing sourced a deal, so management can allocate resources based on which function is sourcing the most pipeline or revenue. Dividing the world into sales or marketing revenue attribution has great appeal for obvious reasons, but it can lead to a distorted picture of how marketing and sales influence pipeline and revenue creation.

Revenue_Attribution_Post_Quote_2.pngThe example above is built on the idea that a business can declare one person as the entire reason a deal happened, to the exclusion of all other people and their engagement that influenced a deal. In reality, most B2B deals involve more than one contact from the buyer, often defined by their role in the decision such as influencer, or primary. Depending on the product or service being sold, a seller might engage with a few people or many dozens. Let’s say for our purposes we’re focused on deals that average five to ten buyer contacts for any opportunity. In order to get a complete accounting for the role marketing played in any opportunity, we have to consider all of the people associated with the opportunity and understand all of the marketing programs they engaged in – like attending webinars, visiting a booth at a trade show – any and all buyer responses to a marketing stimulus.

 

In simple terms, B2B marketers are responsible for 1) adding new names to the marketing database and 2) engaging them through marketing programs. If marketing is successful in pursuing those core missions, some of those people should make their way onto opportunities, some of whom should eventually convert to revenue. The big picture looks like this: marketing adds new names acquired by a number of programs/tactics, and marketing engages people through a range of tactics/programs that change frequently. Compared with single-sourced attribution, the world of multi-touch attribution can get very complicated very quickly.

 

Revenue Attribution the Marketo way

As I stated earlier, the Marketo platform is designed to collect and manage data in a way that lends itself to revenue attribution reporting. Understanding this architecture is the proverbial key to the universe when it comes to getting the full value from your Marketo investment and getting to good analytics. If you already know Marketo, read on anyway because this simplified explanation can come in handy when you have to explain Marketo to the un-indoctrinated.

Channels.jpg

 

Marketo channels are your marketing tactics defined as templates – Webinar, Trade show, Online Advertising and so on. For each channel you must define the actions someone can take – these are called member statuses in Marketo. As an example, the Webinar channel typically includes: Invited, Registered, No Show, Attended, and Attended On-demand. You must also state which member statuses you consider a marketing success. Using Webinar as an example again, you would definitely say people who attend your webinar reached success, but when/if someone only registers – is that a success? It depends if you consider someone registering for a webinar a marketing win; some do, some don’t. Marketo declares all successes are created equal – that is, a webinar success has equal value to a white paper download. This prevents marketers from trying to be too clever at assuming we know which engagement influenced someone more than another.  There are lots of attribution models out there, seemingly more every day – this article is devoted to Marketo’s attribution model.

Revenue_Attribution_Post_Quote_3.jpgThere’s one last component you need to understand to get the Marketo architecture religion: Marketo programs. you must create a program for every webinar, trade show, ad campaign, etc. that you plan to run. Those Marketo channels I explained above? Here’s where they come into play. Every time you create a program, Marketo asks you which Marketo channel to use as the template for the program. If you’re creating a program for a webinar, you pick the Webinar channel; for a trade show – the Tradeshow channel and so-on. After you create a program, you can start adding names to the program as members.  Those member statuses, like Registered and Attended? For every member in a program, you can (and must) build the logic in Marketo to change their member status when they do whatever it is that maps to a member status. For example, someone in a webinar would start with member status is “Invited when you add them to the program, then when you send them an invite the member status needs to change to “invited,” when they register it changes to “Registered” and so on.

 

How you define and use your Marketo channels, member statuses, and which member statuses are successes is the key to defining how you will measure, analyze and optimize your marketing based on marketing analytics. Salesforce has similar architecture design concepts that map to Marketo: Marketo Channels = SFDC Campaign Type, Marketo Channel Member Statuses = SFDC Campaign Member Statuses, and Marketo Success = SFDC Responded. The big differences are, SFDC campaign types are not templatized for re-use, and SFDC does not support the idea of success defined according to each unique channel member status. These seemingly small differences are what give Marketo a big edge in collecting and storing data for reporting. Now you have the essential building blocks to get your Marketo analytics right. I cannot overstate how important it is to get these right, nor how often we see Marketo customers miss on these important elements.

 

Marketo – the game

Think of marketing as a betting game. You start with a plan, placing your bets on the calendar across marketing tactics and campaigns. You bet some of your budget on webinars, some on newsletters, trade shows, paid online advertising – spreading your bets across multiple marketing channels and dates. The dates approach, the programs run, things happen (or don’t). Some programs bring in new names, some engage names already Marketo. How do you know which bets paid off, and which ones didn’t?

Marketo-Opoly.jpg

 

How revenue attribution works

Let’s stick with the assumption that on average, an opportunity has five to ten contacts we engage for any opportunity. Instead of saying any one person or one action gets all the credit for an opportunity, we spread the credit across all of the people associated to an opportunity. If there are five contacts on the deal, we must examine the marketing history of all five contacts to determine the impact marketing had on the deal. If the marketing history for those five contacts shows they were members in twenty Marketo programs, Marketo would examine all of their marketing history in all twenty programs to determine how much credit each program receives for influencing the deal.

Revenue_Attribution_Post_Quote_4.jpgHere’s the big idea: it takes multiple people acquired and engaged by multiple programs across multiple tactics, played out over time to make a deal happen. You have to connect opportunities to people and drill into their marketing history to connect marketing with pipeline and revenue. Many struggle to fully grasp this idea, so I will put this another way: marketing doesn’t invite opportunities to webinars, or talk with opportunities at the trade show booth. If the people they invite to webinars or talk with at the trade show booth eventually become associated to opportunities, Marketo can find the connection between marketing and the opportunity through their actions by First Touch, and Multi-Touch attribution.

 

First Touch – the Marketo program that acquired the person

If the goal of the program was to acquire new names, the measure of success will be how many new names the program added to Marketo. For example, if you setup a program called “March 2018 Google PPC” to collect new names brought in by your Google ad campaigns, and the program added 100 new names in a month, the “March 2018 Google PPC” was a good bet for Marketing to the extent that it added 100 new names. If you setup your program correctly, every name added to Marketo that originated from “March 2018 Google PPC” program will have the program name “March 2018 Google PPC” contained in the Acquisition Program field on the lead record.  This field is a Marketo default field established when you setup Marketo, and an important one at that. If you want to know which marketing tactics/programs performed best to add names to the database, this is the field Marketo uses to answer the question.

Revenue_Attribution_Post_Quote_5.jpgIn the Marketo Revenue attribution model, Marketo calls this First Touch attribution – the program that gets credit for adding a person to the database. In hindsight they probably should have named it “Program Source” or something like that so people wouldn’t misinterpret it to mean the first program that engaged a person. Marketo acquisition program is similar to a lead source because it addresses the question: where did this person come from? But lead source and acquisition program are different – though there is often uniformity between the two, as in the case when a trade show program acquires a name, we can infer the lead source is trade show from the fact that the program that acquired the name is built on the Marketo trade show Channel. In Marketo, you need to have lead sources and acquisition program values assigned every time, and consistently – even when a name is added by a sales person from the CRM. That’s right, you should create a Marketo channel, call it Sales Generated, and create a Marketo program on the channel to collect new names and assign the First Touch credit for new names added by way of the CRM. That way, you can compare the ROI on acquiring names from the CRM with marketing tactics like Online Advertising or Tradeshows.

 

Multi-Touch: the Marketo programs that engaged people to reach success

If the goal of the program was to engage names already in the database to prompt them to take a meaningful action – like attend a webinar – every person reaching success in a program puts that program on the boards for consideration toward sharing in the credit for a deal. Think of Marketo as a board game again. You play the game by placing your marketing bets on the calendar with programs and tactics.  You score early wins when people reach success in your programs (attend, download, etc.). Those successes translate to pipeline and revenue influence. If the object of the game is revenue, the winning strategy is to drive true engagement all the time, where the engagement (Marketo program success) translates to pipeline and revenue influence. Note I said influenced, and not created. Marketing does not create qualified opportunities – marketing engages people some of whom will make it to opportunities. Here is a simple example of a multi-touch scenario.

 

Sue the prospect attends a webinar and downloads a white paper. Bill the prospect downloads the same white paper and attends a live event. Suppose Sue and Bill get added to a $10K opportunity, Marketo will look at Sue and Bill’s marketing history and tally up their successes:

Successes.jpgThat makes four successes total across three programs. Sue and Bill were both in the White Paper program so that program gets 50% of the credit, the other two programs each take 25%.

Analytics.jpgIf the $10K opportunity makes it to closed won, the revenue won amount will be applied by the percentage portion that each program received: $5K to White Paper program, $2.5K each to Live Event and Webinar programs.

Analytics_2.jpgMarketo also splits First-Touch across people, so in this example Marketo would determine the acquisition program for each person and split the first-touch credit accordingly. This was a simple example, as you can imagine the more people involved in a deal, and the more time / engagement that goes by, the more complicated revenue attribution gets. Depending which reporting tool you use, Marketo gives you options to filter and calculate data using different assumptions, including whether to count program successes up to opportunity created date, or through opportunity closed date.

 

Reporting Revenue Attribution in Marketo

Now that you understand the basics of Marketo revenue attribution, you must learn where and how to report revenue attribution.  Before I dive into that, you need to understand how Marketo calculates the numbers and where those calculations are stored. Those calculations are performed nightly and stored in an application and database separate from your Marketo application and data.  Here are the analytics tools Marketo sells to access and analyze the performance data:

  1. Marketo Advanced Reports Builder (ARB) – formerly named Revenue Cycle Explorer (RCE). ARB is a BI tool that uses an Excel-like pivot table metaphor that supports drag and drop to assemble reports, show them as charts and dashboards and a lot more. When you launch ARB from Marketo, you’re firing up a separate program. Don’t go looking for ARB in your Marketo UI, it’s still referenced by its old name Revenue Explorer.

  2. Program Analyzer: An x-y axis chart that lets you pick and choose plots using revenue attribution field and values. Interestingly, this tool has a few calculations that you don’t see anywhere else, like cost per MQL.

  3. Marketo Performance Insights (MPI): this is a new tool offered by Marketo that is purpose-built to make it easy to see program success and revenue attribution packaged in the Marketo Insights UI.

Performance_Insights.jpgWhere ARB gives you the kitchen sink to build anything you want the way you want, MPI provides the essential program performance reports pre-built, with some flexibility provided in the form of drop down filters, and export features. What you trade-off for the complete flexibility you get in ARB, you gain in rapid time to productivity and from my limited experienced so far with MPI, some real-time performance gains on refreshing charts and tables.

 

Marketo Attribution Model Choices

Marketo was early to the marketing attribution game to realize the impact contact attach rate with opportunities (or lack thereof) has on revenue attribution reports. If sales doesn’t add anyone to an opportunity, there’s nobody available for Marketo to consider for marketing influence. So Marketo gives you a configurable setting that determines how it will identify people to associate with opportunities:

  1. Explicit: only count the contact roles associated with opportunities (this is SFDC’s one and only way to make the people connection for its pipeline influence report)

  2. Hybrid: look for a contact role on the opportunity; if it doesn’t find at least one, look at the opportunity company, find the account contacts with and without roles, and consider all of them for influence

  3. Implicit: Look at the opportunity company, find the account contacts with and without roles, consider all of them for influence. Think of this as account-based influence.

When you change the setting, it takes effect in the next overnight data calculation. You can run the numbers under all three settings over the course of three days. Given the time lag, it’s a good idea to plan your reporting well in advance as much as possible.

 

Behind the numbers

If you design your Marketo correctly and apply rigor to process and data every day, you will get revenue analytics that tell you a lot about your marketing that will help you be a smart marketer. If you don’t, you may expose yourself to revenue analytics that will tell an incomplete, or inaccurate story – and you may not even realize it. Even one bad list import can have a detrimental impact on your reports. Here is my attempt to list the data and process areas you need to consider:

Analytics_Issues.jpgThere may well be more I have not listed here. What’s the biggest room in the world? Room for error when it comes to revenue analytics (not just Marketo, any revenue analytics). It is possible to control these challenges, but you need to be aware of them, monitor for them, and get everyone on board to keep your data clean.

A final word about attribution reporting

It isn’t enough to understand how this all works. It isn’t enough to get your data right and keep it right.  If you understand Marketo revenue attribution, and you get your data right, and you build the standard set of reports -- you still have the most formidable challenge ahead of you: getting your organization to understand, buy into, and use the reports to continuously optimize marketing ROI. If marketing needs its own language – and it does – it’s marketing analytics. There’s a lot more to making marketing analytics the common language of marketing in an organization than I can cover here. It’s a subject I have a lot to say about in the forthcoming May 2018 issue of Applied Marketing Analytics: "How organizations can establish marketing analytics as the common business language to drive continuous improvement."

 

Originally posted on LinkedIn on April 24, 2018

When choosing a Thank You/Follow Up URL, Form Editor presents 3 largely self-explanatory options:

ss

Choosing Landing Page will give you a nice dropdown of all your approved Marketo LPs.

Choosing External URL and entering the full URL of a Marketo LP seems to work, too — but it's a bad move. Form Editor won't tell you why, but I will.

The problem

If you choose Landing Page or Stay on Page, Marketo uses a special read-your-write feature to ensure Pre-Fill on the next pageview.[1]

If you choose External URL, Marketo looks up the URL in your known LPs but it doesn't look in your Redirect Rules.  If the URL is not seen as a core LP URL, even if it does lead to a Marketo LP in reality, then the read-your-write Pre-Fill cache is not enabled.

What is “read-your-write” and why should I care?

“Read-your-write” or RYW is a desirable, but not always supported, feature of distributed systems. (A distributed system is any system that processes data at multiple tiers, like we all know Marketo does.)

RYW, in a nutshell, means:

If a user thinks they've made a change to the back end, then show them the new data as if it's been fully saved, regardless of whether system(s) may be still filtering and processing — or even discarding! — the data in the background.

It doesn't mean anybody else sees uncommitted data (there are some cases in which it won't be saved, so you don't want to propagate bad info more widely than necessary).

It means that for a less confusing user experience, you let a user see their own requested update immediately, instead of forcing them to see older saved data for a few seconds/minutes (even though showing saved data would technically be more accurate end-to-end).

Marketo implements read-your-write via the special query parameter aliId. It's a numeric identifier for a set of submitted form values, and it's usable regardless of whether the values are actually saved. When a page has an aliId in the URL, it's capable of (for the most potent example) filling a second form using the data from a first form, even if it was submitted mere milliseconds before.

Back to Form Editor

When you choose External URL in Form Editor, Marketo tries to append the aliId intelligently, but it can't know about your redirects (especially 3rd-party redirects) or anything that might disguise the Marketo-ness of the destination URL.  As a result, the next LP someone views may show their session's old data (maybe including someone else's email) or no data at all (the session still being effectively anonymous). You don't want that! So choose Landing Page if it's indeed a Marketo LP.

Other complications

When you use the Forms JS API onSuccess method to choose a Thank You URL dynamically (a very powerful option) set the form to Stay on Page in Form Editor, as this will ensure the aliId is appended.

Then clip out and append the original query string, which will include the aliId, to the dynamic URL.

A quick-and-dirty way to append the original query is like so:

MktoForms2.whenReady(function(form){
  form.onSuccess(function(vals,tyURLFromFormEditor){
    var originalThankYouDoc = document.createElement("a");
    originalThankYouDoc.href = tyURLFromFormEditor;
    
    var dynamicThankYouURL = "https://pages.example.com/other-marketo-lp.html" + 
      originalThankYouDoc.search;
    
    document.location.href = dynamicThankYouURL;
    return false;
  });
});

If you're using a fuller-featured URI parser/builder already, like uri.js, use that instead of the Link/Location method (though the location.search breakdown works perfectly, since it's a key browser function).

Just don't write your own parser… I don't want to have to holler at you again!


NOTES

[1] When you use Stay on Page the aliId is attached even if you're using the form embed and the page is a non-Marketo page. It's not fully honored in this case (since Pre-Fill isn't supported with the embed) but it's better to have it there than not.

University Day.png

 

It's not too late to register for University Day!

 

Accelerate your Marketo learning at the Marketing Nation Summit 2018! Join us at University Day on April 29, 2018, where you can take your Marketo skills to the next level and build expertise will focused instruction, practical demonstrations, and inspiring presentations by our Marketo experts.

 

Register Now and add to your Summit registration!

 

In the Bay Area but can't make it to the full four days of Summit?

Check out our University Day Single Day Pass. Register Now

Little-publicized, to the point that even Support might not be in the loop: the Visibility Rule Contains operator does allow multiple values.

The Contains value is interpreted as a full-fledged regular expression, so use the pipe character | to separate sub-values:

ss

In fact, because of this unexpected/undocumented power, you must anchor an expression to avoid surprises:

^(TX|FL|PA)$ 

Otherwise, it's doing a partial match of the full value against each of your pipe-delimited alternatives. This might not be a problem on your forms right now, but if it becomes a problem, you wouldn't know about it immediately.

For example, if you were using uppercase state names, then

     Contains KANSAS|IDAHO

would match both ARKANSAS and KANSAS, and you should use

     Contains ^(KANSAS|IDAHO)$

instead.

You can also of course do more fancy matches with regexes if you want. And Not Contains is also a regex!

There are 2 ways to access references (i.e. variables) in Velocity.

 

(1) Simple/shorthand notation, prefixed with a $:

 

$variableName
$variable.property
$variable.method()
$variable.property.method()

 

(2) Formal/longhand notation, prefixed with $ and wrapped in {} (curly braces):

 

${variableName}
${variable.property}
${variable.method()}
${variable.property.method()}

 

Simple notation should be your default. Formal notation should only be used when there's no alternative. As the Velocity docs say:

 

In almost all cases you will use the shorthand notation for references, but in some cases the formal notation is required for correct processing.

 

I'd go further: when used unnecessarily, formal notation can make your code confusing and fragile. Unfortunately, Marketo's script editor doesn't encourage best practices, because when you drag a field from the field tree to the editor canvas, it's automatically  wrapped in ${}:

 

5acbd8e898b1d0002262929b_vtl_formal_scripted.png

My recommendation: remove the curly braces right away, and only restore them if it proves necessary during development.

 

What can go wrong?

A recent Community post shows how confusing things can get when you use formal notation unnecessarily (note how the poster titled it "... tokens behave unexpectedly" when it's actually established behavior, if not well-circulated).

 

The catch: a reference enclosed in ${formal.notation} cannot be chained with a method/property outside the curly braces.

 

OK, that probably didn't make sense unless you're fluent in OO-speak! Let's look at some examples.

 

This does work with simple notation:

 

#if( $lead.FirstName.isEmpty() )

 

It doesn't work if you only enclose part of the expression in formal notation:

 

#if( ${lead.FirstName}.isEmpty() )

 

Sure, it would work if you happened to enclose the entire expression in curlies

 

#if( ${lead.FirstName.isEmpty()} )

 

but you should just use simple notation instead, because it's harder to mess up during refactoring.

 

Don't believe me? (You probably do, or I'd like to hear who's more authoritative about Velocity.) Consider what happens when you move from a not-best-practice, but syntax-error-free, comparison using double-equals ==:

 

#(if ${lead.numberOfProducts} == 0 )

 

to a more forward-looking equals():

 

#if( ${lead.numberOfProducts}.equals(0) )

 

Suddenly, your Velocity token stops working because you can't have a . after a }. It may be clear, to you as a human, what you meant, but VTL doesn't allow it. If you'd used simple notation from the start you wouldn't have to make such adjustments.

 

When do you need to go formal?

Formal notation should only be considered inside strings or output, and only used when the separation between variables and static text would otherwise be unclear.

 

If you're in a line of code starting with #if or #set chances are very slim that you should be using formal notation.

 

Here's one case where it is necessary...

 

Read the full post on

You've seen before that the Forms 2.0 input mask plugin can be tweaked to do some more elegant stuff.

Here are a few more things you might want to do. I only recommend masks for things that have an explicit standard (like phone numbers, credit cards, etc.). But if you're going to use them for more than that, use them wisely!

The code is bundled at the bottom of the post.

SUPPRESS THE UNDERSCORE AS THE PLACEHOLDER

By default, the mask shows a _ character in every empty position up to the max length.

This can look ugly, especially if there's already a hint in the field telling people it's limited to N characters.

ss

You can remove the placeholder character entirely or replace it with something else (though I'm not sure anything is better than underscore or blank in this case, maybe a cursor block like ░ if you want to be retro-cool?).

ACCEPT ANY LATIN-1 LETTER, NOT JUST A-Z AND a-z

When you select the a shortcut in the Form Editor…

ss

… you're actually blocking all but the slimmest subset of alphanumeric characters.Even the e-with-acute-accent in Grégoire is blocked! That's not good when words contain these slightly out-of-the-American-ordinary characters.

It works this way because, under the hood, input masks use the regex character class [A-Za-z] to implement a. And that's ASCII unaccented letters only.

The better move is to use a class like [A-Za-z\u00C0-\u024F] which includes Latin accented letters, i.e. those from Romance languages. (You'll still be blocking people who spell their names using other glyphs, but that's another matter.)

Better still, if you're in the world of names, allow hyphens, apostrophes, periods, and spaces: [A-Za-z\u00C0-\u024F'. -].

ALLOW SPACES, NOT JUST CHARACTERS

When you set a mask to **********, even if you don't want non-ASCII, non-accented characters, do you really mean that spaces aren't allowed? Sometimes yes, sometimes no.

In the case of ISBN-10s, for example, no spaces are allowed per the international standard, and you might want to block spaces in the Phone field for standardization.

But in the case of First or Last Name, Company, or tons of other cases, you certainly don't want to block spaces.

MAKE IT HAPPEN

All of the above functions can be enabled with the helper JS below.

First, in Form Editor, give each field you want to re-mask an initial mask (any mask pattern will do). (If it isn't masked to begin with, we can't tweak the mask setup.)

Then add your custom patterns to the inputMasks array as below: the name property is the Marketo form field name and the rest is explained in the comments.

 

(function() {
   MktoForms2.$("body").on("mkto_inputmask_polyfilled", function(e) {
      var inputMasks = [
         {
            name: "Title",
            maskPattern: "ssssssssss", // 10 [A-Za-z ] letters or spaces
            maskCharPlaceholder: "" // no placeholder char
         },
         {
            name: "Nickname",
            maskPattern: "nnnnnnnnn", // 10 [A-Za-z0-9 ] chars or spaces
            maskCharPlaceholder: "" // no placeholder char
         },
         {
            name: "Interest",
            maskPattern: "cccccccccc", // 10 Latin letters or (some) Latin puncuation marks
            maskCharPlaceholder: "░" // alternate placeholder char to show how it's done
         }
      ];

      /* --- NO NEED TO TOUCH BELOW THIS LINE! --- */

      MktoForms2.whenReady(function(form) {
         var maskCharExtensions = {
            c: "[A-Za-z\u00C0-\u024F'. -]",
            s: "[A-Za-z ]",
            n: "[A-Za-z0-9 ]"
         };

         Object.keys(maskCharExtensions)
            .forEach(function(char) {
              MktoForms2.$.mask.definitions[char] = this[char];
         }, maskCharExtensions);

         inputMasks
            .map(function(field) {
               field.el$ = form
                  .getFormElem()
                  .find("[name='" + field.name + "']");
               return field;
            })
            .forEach(function(field) {
               var mask =
                     typeof field.maskPattern != "undefined"
                        ? field.maskPattern
                        : field.el$.data("mktoInputMask"),
                  placeholder =
                     typeof field.maskCharPlaceholder != "undefined"
                        ? field.maskCharPlaceholder
                        : MktoForms2.$.mask.placeholder;

               field.el$.mask(mask, { placeholder: placeholder });
            });
      });
   });
})();

Be sure you sign up for as many of these 18 (2X more than at Summit 2017!!!) fabulous Marketo Technical & Foundational Techniques track sessions from our very own amazing Marketo Champions and Champion Alumni as you can:

  1. Analytics That Matter: Reports For Every Stage of the Funnel -- Jessica Kao
  2. AWSome Sauce: 10 Marketo Life Lessons From An Enterprise Org -- Joe Reitz
  3. Beyond Channels: What Else To Use To Capture The Data You Really Need (Workshop) -- Emily Thornton, Jenny Robertson, & Taylor Enfinger
  4. Cut me some Slack! Leveraging The Slack API With Marketo Webhooks And Bots -- Erik Heldebro
  5. Don't Get Lost In The Upside Down Of Your Sales Funnel (Workshop) -- Chelsea Kiko & Chris Saporito
  6. Email Deliverability 101: Winning The Inbox Wars (Workshop) -- Carmi Lopez-Jones & Kiersti Esparza
  7. Fearless Marketing In A GDPR World: Tips To Thrive Amidst New Regulations -- Michelle Miles
  8. From Nurture To Negotiation: Intelligent ABM In 2018 (Workshop) -- Rachel Noble
  9. How To Build A Marketing Operations Center Of Excellence (Workshop) -- Andy Varshneya & Edward Unthank (ETU)
  10. Infrastructure Down & Dirty: Architecting Best Practices In Marketo -- Edward Unthank (ETU)
  11. Make The Most Out Of Your A/B Testing: What Every Data Driven Marketer Needs To Know (Workshop) -- Jessica Kao
  12. Master Engagement Marketing With Marketo Engagement Programs -- Josh Hill
  13. Passing The Baton: How to Track Sales Follow Up On Your Marketing Leads (Workshop) -- David Da Silva & Mark Farnell
  14. Rolebased Metrics: The Right Report For The Right Stakeholder At The Right Time -- Veronica Holmes
  15. Skinning Schrodinger’s Cat: Fearless Marketing When You Don’t Know What You Don’t Know -- Jenn DiMaria & Juli James
  16. Smash The Data Silos: Use Marketo To Create A Single Source Of Customer Truth -- Courtney Grimes, Eric Hollebone, & Gary DeAsi
  17. Strengthening Sales & Marketing Alignment: Developing Real-Time Alerts with Rich, Actionable Insights (Workshop) -- Dan Stevens
  18. Web Personalization & ContentAI In The Real World: A Marketer's Tale -- JD Nelson

 

The number one thing we heard from you in your feedback from Summit 2017 was that you wanted more workshops! As you can see, we are offering eight of the above content sessions as workshops where you have the opportunity for a more intimate and interactive session with our most experienced speakers.

 

See you at the Marketing Nation Summit!

Boolean type fields enjoy a strange place in Marketo's Velocity implementation.

On the Marketo UI side and via most Marketo APIs, Booleans hold consistent true/false values (presumably using SQL bit type fields under the hood).

But in Velocity, as I've explored before, a Boolean field is presented as one of two Strings:

  • "1" for Boolean true
  • "" (empty string) for Boolean false

That conversion is actually really confusing.

See, Velocity inherits a lot of things (variable handling things) from Java.

In Java, a non-null String object, on its own, is always evaluated as Boolean true. Regardless of whether it has any characters in it (that is, regardless of whether it's empty).

So if you do:

#if( $lead.someBooleanField )
Field is true
#else
Field is false
#end

You will always get “Field is true” even if you've unchecked the corresponding checkbox in the Marketo UI.

If Marketo Booleans were Velocity/Java Booleans, on the other hand, this would've worked fine. But alas.

So the question is what to do with these sort-of-Boolean-like-Strings (whose meaning we understand, but the VTL language doesn't). What do we convert them to to make them more usable?

You can do a step-by-step conversion to Boolean by doing a String comparison:

#if(  $lead.someBooleanField.equals("1") )
#set( $lead.someBooleanField == true )
#else
#set( $lead.someBooleanField == false )
#end

After that conversion, #if($field) will work as expected.

But I've been thinking lately that maybe converting those Strings to Numbers — 0for false and 1 for true, as the standard goes — gives us more juice within Velocity than if we were to go with true Booleans.

 

 

Read the full post on TEKNKL :: Blog →

Summit is just a little over a month away (April 29th-May 2nd) and you don’t want to miss out! Make sure you have your pass so you can join us in San Francisco to learn from marketers like you who share similar goals and have fearlessly faced similar challenges:

  • Sendgrid’s Jacob Hansen sharing best practices for maximizing your email deliverability
  • SiriusDecision’s John Donlon on proven steps to a successful ABM implementation
  • Uber’s Wyatt Bales on building a next-gen Marketing Operations organization
  • Hands-on workshops on A/B testing and Advanced Reporting with Digital Pi’s Jessica Kao
  • CenturyLink’s Scott Berns on how they keep their robust database healthy
  • Meet ups for financial services, healthcare, manufacturing, higher ed marketers like you

 

This year we’ve doubled the amount of technical Marketo content! Check it out.

 

Who's going to be there? 

    Velocity is the only language where Brevity for Brevity's Sake is OK.

    In other languages, reducing total lines of code (LOC) with show-offy shortcuts just means your code will make no sense (to you or anyone else) after a few months away.

    But in Velocity, the shortest possible implementation is a smart move, since:

    • VTL is verbose (only one major operation permitted per line, temp variables required even for void methods)
    • it offers limited reusability (especially Marketo's flavor of Velocity, where #macro and reused $references don't work consistently)
    • it's completely whitespace-preserving (indenting would help readability, but messes up output — so the fewer lines, the less to mess up)
    • the more lines of code in your template, the more distraction from the “meat,” which is the output

    Imagine you had a few Lead fields using the JETDS naming system: installationEnvironment, typeOfEquipment, and purpose.

    There are 10-20 options for each of these fields, so the number of total combinations is huge. Even if you're only interested in a subset, the conditions get loooooong...

 

#* 
I'm being generous with whitespace here, 
but it's *still* hard to read/maintain! 
VTL is whitespace-preserving, so indents are true spaces.
*#
#if( $lead.installationEnvironment == "amphibious" )
 #if( $lead.typeOfEquipment == "radar" )
   #if( $lead.purpose == "receiving" )
   do something...
   #elseif( $lead.purpose == "detecting" )
   do something else...
   #elseif( $lead.purpose == "navigation-aid" )
   do something else entirely...
   #end
 #elseif ( $lead.typeOfEquipment == "sonar" )
   #if( $lead.purpose == "receiving" )
   do yet another thing...
   #elseif( $lead.purpose == "detecting" )
   do still another thing...
   #elseif( $lead.purpose == "navigation-aid" )
   ...
   #end
 #end
#elseif( $lead.installationEnvironment == "ground-mobile" )
 #if( $lead.typeOfEquipment == "radar" )
   #if( $lead.purpose == "receiving" )
   ...
   #elseif( $lead.purpose == "detecting" )
   ...
   #elseif( $lead.purpose == "navigation-aid" )
   ...
   #end
 #end
#end
## etc., etc.

 

Read the full post on TEKNKL :: Blog →

Y'all have seen this type of double-confirmation popup, I'm sure:

ss

It's helpful if you want to give end users a little additional nudge, for example to use their legal name, a working email address, and so on — stuff that you can't force them to do but maybe can guilt them into.

No one but me would claim it's “easy” to add this functionality to a Marketo form. It only took an hour to whip it up, but as you know, I waste spend more time in Forms 2.0 API-land than anybody else. I've provided a big leg up: a working CodePen you can spin off for your own site.

Most of the heavy lifting is done in CSS: overlaying the background, positioning the popup bar, changing the color of the Cancel/Go Back button. Aside from managing the visibility of the bar (display: block or display: none) there's not a huge amount happening in JavaScript.

 

 

Read the full post on TEKNKL :: Blog →

Welcome to 2018! We’re starting the new year out on a positive note by rolling out a new design and structure in the Marketing Nation Community with the goal of helping you be more successful with Marketo, more quickly. The new design and structure was reviewed and vetted by many Community members and we truly appreciated all their valuable feedback.

 

Starting next new week, you will see:

  1. A new home page experience – When you land on the home page, you’ll see a news feed of what’s new and exciting in the Marketing Nation Community. For those of you who have been part of Marketing Nation for several years, it will be like going back to the good ‘ol days. The Marketo banner has also been removed so you have immediate access to what you really care about, the exciting and helpful conversations happening among your fellow Community members.
  2. One place for discussions – You asked and we answered. No more decisions about where to look for answers to your questions. Product Discussions and Marketing Discussions have been merged into a single place to access the genius of your fellow marketers, simply called Discussions.
  3. A new Blog space – Read about best practices, tips and tricks, and more from peers, experts, and Marketo employees…all in one spot.
  4. An area for Release Info – Want to learn about what’s in the latest, greatest Marketo release? Look no further than our new Release Info space. 
  5. Mobile friendly – Guess what? The Marketing Nation is now mobile friendly so you can take it on the go with you. The genius of your peers is always at your fingertips.

 

I’m excited to roll out these changes to Marketing Nation. As always, if you have any additional ideas or feedback, please feel free to let me know.

 

You can expect the Marketing Nation Community to keep getting better and better throughout 2018!

Filter Blog

By date: By tag: