DEV Community

The AMPscript Ninja
The AMPscript Ninja

Posted on • Originally published at ampscript-ninja.hashnode.dev

Calculating A Percent vs. A Goal With SFMC's AMPscript

How many year-end review emails did you get this year? Ever since Spotify Wrapped first made waves, it feels like more and more brands have tried to recreate the same hyper-personalized feel, my company included. One of the questions that came up from my team this year:

Can we calculate a percentage comparing someone’s actual progress this year against a goal, or against their actual progress last year?

Absolutely! In this article I’ll give you all the AMPscript you need. And to have even more fun, I’ll show you how to reuse those percentages in dynamically sized HTML progress bars.

Percentages In AMPscript

The first thing we’ll do is select what is being compared — progress vs. a goal, this year vs. last year, personal performance vs. community average, etc. This can be anything you want as long as it’s a number format.

To keep things simple for this example, I’m going to do two sets of progress vs. a goal, and for example purposes I will just hard code some values — one under goal, one over.

%%[
    /* GOAL 1 */
        set @actual1 = "421"
        set @goal1 = "500"

    /* GOAL 2 */
        set @actual2 = "523"
        set @goal2 = "500"
]%%
Enter fullscreen mode Exit fullscreen mode

Second, we’ll use Divide() to get the progress as a decimal.

set @percentage1 = Divide(@actual1,@goal1)
set @percentage2 = Divide(@actual2,@goal2)
Enter fullscreen mode Exit fullscreen mode

Results: 421 / 500 = 0.842, and 523 / 500 = 1.046

Third, we’re going to use Multiply() by 100 to turn our decimals into percentages.

set @percentage1 = Multiply(@percentage1,100)
set @percentage2 = Multiply(@percentage2,100)
Enter fullscreen mode Exit fullscreen mode

(You’ll notice I’m using set on the same variable again — that is supported, if you want to do that to make iterative changes to the same variable. When we get to the end, I’ll give you a single consolidated line with all transformations, but for now let’s keep the steps separate so we can see what each one is doing.)

Results: 0.842 × 100 = 84.2, and 1.046 × 100 = 104.6

We’re getting close, but depending on how large your numbers are, you may end up with a lot of decimal points — so fourth, let’s reformat as a whole number (‘N’) with zero decimal points (‘0’).

set @percentage1 = FormatNumber(@percentage1,'N0')
set @percentage2 = FormatNumber(@percentage2,'N0')
Enter fullscreen mode Exit fullscreen mode

This rounds us to a clean 84 and 105, perfect for showing percentages.

At this point you can use this in your email content; e.g. “You completed 84% of your goal”, but for positive numbers “You completed 105% of your goal” feels a little odd. It feels more natural to use a percentage beat or missed, so let’s calculate that next.

We’ll use Subtract() to take away 100, which will leave us with a positive or negative number less than 100.

set @percentage_beat1 = Subtract(@percentage1,100)
set @percentage_beat2 = Subtract(@percentage2,100)
Enter fullscreen mode Exit fullscreen mode

Results: 84 - 100 = -16, and 105 - 100 = 5

After a quick Replace() to strip off the - (if present)…

set @percentage_beat1 = Replace(@percentage_beat1,'-','')
set @percentage_beat2 = Replace(@percentage_beat2,'-','')
Enter fullscreen mode Exit fullscreen mode

…we’re left with the final numbers, 16 (percent) under, and 5 (percent) over.

Before we get into how to use those final numbers in the email content, here is the complete view of all these steps together.

%%[
/* PERCENTAGE TO GOAL */
    /* GOAL 1 */
        set @actual1 = "421"
        set @goal1 = "500"

        set @percentage1 = Divide(@actual1,@goal1)                   /* Divide the actual vs. the goal */
        set @percentage1 = Multiply(@percentage1,100)                /* Multiply by 100 for a percent */
        set @percentage1 = FormatNumber(@percentage1,'N0')           /* Format as a whole number 'N' with 0 decimal points */
        set @percentage1 = Replace(@percentage1,',','')              /* Remove commas if exceeding 1000 */

        set @percentage_beat1 = Subtract(@percentage1,100)           /* Subtract 100 to get over/under */
        set @percentage_beat1 = Replace(@percentage_beat1,'-','')    /* Remove the '-' sign, if negative */
]%%
Enter fullscreen mode Exit fullscreen mode

And as promised, here is the consolidated version, with all of the functions working in layers from the inside to the outside.

/* GOAL 3 */
        set @actual3 = "421"
        set @goal3 = "500"

        set @percentage3 = Replace(FormatNumber(Multiply(Divide(@actual3,@goal3),100),'N0'),',','')
        set @percentage_beat3 = Replace(Subtract(@percentage3,100),'-','')
Enter fullscreen mode Exit fullscreen mode

Presenting The Results

Let’s evaluate those results to show a summary message. We’ve got 4 possible scenarios:

  1. The goal was met at exactly 100% (== is equal to)

  2. The goal was beat, over 100% (> is greater than)

  3. The goal was missed, below 100% (< is less than)

  4. The goal had no progress at all (else default)

So let’s hit some if/then statements:

if @percentage1 == 100 then
    set @result1 = 'You met your goal &ndash; great work!'
elseif @percentage1 > 100 then
    set @result1 = Concat('You beat your goal by ',@percentage_beat1,'% &ndash; nice work!')
elseif @percentage1 < 100 then
    set @result1 = Concat('You missed your goal by ',@percentage_beat1,'% &ndash; try again next year!')
else
    set @result1 = 'You may not have worked toward this goal this year, but try again next year!'
endif
Enter fullscreen mode Exit fullscreen mode

This allows the summary sentence about each goal’s progress to be dynamic based on their results.


Dynamic HTML Progress Bars

Just for fun, let’s briefly play with one of my favorite AMPscript concepts — using AMPscript inside HTML/CSS. Since we have variables with percentages, we can use those variables for percentage-based HTML table cell widths to create a status bar that is partially or fully colored based on goal progress.

Here’s a picture of my proof of concept to help you visualize what we’re building:

screenshot

First, we’ll evaluate the goal progress to create variable colors and widths.

If it’s at/above 100, then we’ll:

  • Apply a green color
  • Set the width of the complete bar to an even 100
  • Set the width of the incomplete bar to 0, and hide it later

If it’s below 100, then we’ll:

  • Apply a blue color
  • Set the width of the complete bar to the actual progress percentage
  • Set the width of the incomplete bar to the remainder (100 minus progress)
%%[
    /* STATUS BARS */
        if @percentage1 >= 100 then
            set @percentage1_color = '#009933'
            set @percentage1_complete_width = 100
            set @percentage1_incomplete_width = 0
        else
            set @percentage1_color = '#0099ff'
            set @percentage1_complete_width = @percentage1
            set @percentage1_incomplete_width = Subtract(100,@percentage1)
        endif

        if @percentage2 >= 100 then
            set @percentage2_color = '#009933'
            set @percentage2_complete_width = 100
            set @percentage2_incomplete_width = 0
        else
            set @percentage2_color = '#0099ff'
            set @percentage2_complete_width = @percentage2
            set @percentage2_incomplete_width = Subtract(100,@percentage2)
        endif
]%%
Enter fullscreen mode Exit fullscreen mode

Now let’s put those variables into some HTML. Notice the td cells are being populated with dynamic width, bgcolor, and background values.

<table width="600" align="left" cellspacing="0" cellpadding="0" border="0">
    <tr>
        <td width="600" align="left">
            <br />Goal 1: %%=v(@actual1)=%% vs. %%=v(@goal1)=%% = %%=v(@percentage1)=%%%
            <br />--> %%=v(@result1)=%%
        </td>
    </tr>
    <tr>
        <td width="600">
            <table width="600" align="left" cellspacing="0" cellpadding="0" border="0">
                <tr>
                    <td width="%%=v(@percentage1_complete_width)=%%%" align="right">
                        %%=v(@percentage1)=%%%
                        <div style="font-size: 6px; mso-line-height-rule: exactly; line-height: 6px;">&nbsp;</div>
                    </td>

                    %%[if @percentage1_incomplete_width > 0 then]%%
                    <td width="%%=v(@percentage1_incomplete_width)=%%%"></td>
                    %%[endif]%%
                </tr>
                <tr>
                    <td width="%%=v(@percentage1_complete_width)=%%%" bgcolor="%%=v(@percentage1_color)=%%" style="background: %%=v(@percentage1_color)=%%;">
                        <div style="font-size: 18px; mso-line-height-rule: exactly; line-height: 18px;">&nbsp;</div>
                    </td>

                    %%[if @percentage1_incomplete_width > 0 then]%%
                    <td width="%%=v(@percentage1_incomplete_width)=%%%" bgcolor="#bbbbbb" style="background: #bbbbbb;">
                        <div style="font-size: 18px; mso-line-height-rule: exactly; line-height: 18px;">&nbsp;</div>
                    </td>
                    %%[endif]%%
                </tr>
            </table>
        </td>
    </tr>

    <tr>
        <td width="600">
            <div style="font-size: 18px; mso-line-height-rule: exactly; line-height: 18px;">&nbsp;</div>
        </td>
    </tr>

    <tr>
        <td width="600" align="left">
            <br />Goal 2: %%=v(@actual2)=%% vs. %%=v(@goal2)=%% = %%=v(@percentage2)=%%%
            <br />--> %%=v(@result2)=%%
        </td>
    </tr>
    <tr>
        <td width="600">
            <table width="600" align="left" cellspacing="0" cellpadding="0" border="0">
                <tr>
                    <td width="%%=v(@percentage2_complete_width)=%%%" align="right">
                        %%=v(@percentage2)=%%%
                        <div style="font-size: 6px; mso-line-height-rule: exactly; line-height: 6px;">&nbsp;</div>
                    </td>

                    %%[if @percentage2_incomplete_width > 0 then]%%
                    <td width="%%=v(@percentage2_incomplete_width)=%%%"></td>
                    %%[endif]%%
                </tr>
                <tr>
                    <td width="%%=v(@percentage2_complete_width)=%%%" bgcolor="%%=v(@percentage2_color)=%%" style="background: %%=v(@percentage2_color)=%%;">
                        <div style="font-size: 18px; mso-line-height-rule: exactly; line-height: 18px;">&nbsp;</div>
                    </td>

                    %%[if @percentage2_incomplete_width > 0 then]%%
                    <td width="%%=v(@percentage2_incomplete_width)=%%%" bgcolor="#bbbbbb" style="background: #bbbbbb;">
                        <div style="font-size: 18px; mso-line-height-rule: exactly; line-height: 18px;">&nbsp;</div>
                    </td>
                    %%[endif]%%
                </tr>
            </table>
        </td>
    </tr>
</table>
Enter fullscreen mode Exit fullscreen mode

Disclaimer: This is a loose proof of concept. It’s far from elegant HTML, but it shows the rough idea.

And here is our visual again of how it comes together:

screenshot

Using this concept, there is a lot more you could do here to make it more elegant:

  • Separate bars for goal vs. actual
  • Numbers displayed inside the bars
  • Repeating background images or possibly even an animated GIF to add texture/creative to the bars

However you want your design to look, blending AMPscript with HTML/CSS allows dynamic colors and sizes of elements with nothing but code.


I hope you found this helpful — if you have additional ways you’ve used AMPscript for percentages or dynamic email design, leave them in the comments!

Top comments (0)