Over The Hedge: What’s Beyond The Hedge

Author: Ben Woodard
Date: August 02, 2022

Agenda

  • adobeanalyticsr
    • Authentication
    • Pulling Data
    • Building Segments
  • cjar
    • Authentication
    • Key Differences
  • Wrap Up
    • Use Cases
    • What’s Next

Created By Analysts For Analysts

Downloads for adobeanalyticsr

Authentication

What are the options?

Oauth

Open Authentication

  • Based on your profile access
  • Less control
  • Interactive authentication flow
  • Setup is really fast

JWT

JASON Web Token

  • Based on the JSON Web Token access
  • More control
  • Non-interactive authentication flow
  • Harder to setup

Creating the Project

  1. Navigate to the following URL: https://console.adobe.io/integrations.
  2. Click the Create New Project button and select Empty Project
  3. Click the Add API button.
  4. Select the Experience Cloud product icon and then choose Adobe Analytics and click Next.

The next series of steps depends on your choice of authorization.

OAuth Setup Process

  1. Select the OAuth option and then click Next.
  2. Select Web as the platform where you want the integration.
  3. Add Default redirect URI https://adobeanalyticsr.com/token_result.html*.
  4. Add Redirect URI pattern https://adobeanalyticsr.com/token_result.html*.

JWT Setup Process

  1. Select the Service Account (JWT) options and then click Next.
  2. Click on the Generate a Key Pair button. A config file will download onto your desktop.
  3. Select the product profiles to be included in the access and click Save configured API.

Setup Your R Environment Variables

The .Renviron file is an easy way to manage global variables. Global variables are mostly used in packages that rely on some sort of authentication process such as adobeanalyticsr or GoogleAnaltyicsR.

usethis::edit_r_environ('user')

Add the following variables to the file, save it, and restart your R session. (command/ctrl + shift + F10)

Oauth

AW_CLIENT_ID=[Client ID]
AW_CLIENT_SECRET=[Client Secret]

JWT

AW_AUTH_FILE=[auth_file.json]
AW_PRIVATE_KEY=[private.key]

Hot Tip 1

Non-mandatory global environment variables.

Assigning these two optional variables in the .Renviron file can save you a lot of time. If you are working with different companies and report suites then assigning it in the project itself is going to be the best option.

AW_COMPANY_ID=[Company ID]
AW_REPORTSUITE_ID=[RSID]

Finally! Let’s Authenticate

Oauth Authentication

library(adobeanalyticsr) #load the package into the session
aw_auth_with('oauth') #define the type of authentication
aw_auth() #run the authentication function 
Successfully authenticated with OAuth

This function will initiate the authentication dance.

JWT Authentication

library(adobeanalyticsr) #load the package into the session
aw_auth('jwt') #define the auth type in the authentication function 
Successfully authenticated with JWT: access token valid until 2022-08-02 14:24:51

No dance on this one!

Authentication is complete!

When using OAuth authentication, I have access to 12 different accounts.


When using JWT authentication, I only have access to 1 account, Search Discovery, because that is the account the token was setup under.

  globalCompanyId      companyName
1         search9 Search Discovery

Getting Started Functions

Define the Company ID

Now that we have authenticated, we need to define the Company ID and Report Suite we are going to pull data from.

get_me()

Hot Tip 2: Find the company id

The easiest way to find the Company ID is to use the name you find in Workspace on the top right. By filtering results by this name you can pull the globalCompanyId and save it as an object to be used in future API calls.

company_id <- get_me() %>%
  filter(companyName == 'Search Discovery') %>%
  pull(globalCompanyId)

Find the company name

Define the Report Suite

Next, you will need to identify the ID for the appropriate Report Suite. Use the aw_get_reportsuites() function to help you find this.

rsids <- aw_get_reportsuites(company_id='search9')

Hot Tip 3: Find the report suite id

The easiest way to find the report suite id (RSID) is to pull all the report suites in the comapny and then filter using the grepl() function.

id <- aw_get_reportsuites(company_id = company_id, expansion = 'name', limit = 1000) %>%
  filter(grepl('SDI Website 2020 Production', 
               name)) %>%
  pull(id)

Find the RSID

Super Hot Tip 4: Debugger

I often find that new accounts/engagements have at least 1 relevant project created already. This allows me to use the debugger in the Workspace Project to find all the account information I need.

enable the debugger

click on the bug

Find the RSID and Company Id

Pulling Data

Metrics

aw_get_metrics()
id name type
averagepagedepth Average Page Depth int
averagetimespentonpage Average Time Spent on Page (seconds) int
averagetimespentonsite Average Time Spent on Site (seconds) int
averagevisitdepth Average Visit Depth int
bouncerate Bounce Rate percent
bounces Bounces int

Dimensions

aw_get_dimensions()
id title description
averagepagetime Time Spent on Page - Bucketed NA
browser Browser NA
browserheight Browser Height - Granular NA
browserheightbucketed Browser Height - Bucketed NA
browsertype Browser Type NA
browserwidth Browser Width - Granular NA

Calculated Metrics

Calculated metrics have really long id names which make it hard to find. Since names can be identical across different calculated metrics, this function is a big help in identifying the correct calculated metrics you are looking for.

aw_get_calculatedmetrics()
rsid id name
sdptnradamtest1 cm300003965_557fc577e4b07e827d177ad0 Crash Rate (Mobile)
sdptnradamtest1 cm300003965_557fc577e4b07e827d177ad3 Average Session Length (Mobile)
sdptnregan cm300003965_557fc578e4b0094eea4f5201 Single Access (Calculated)
sdptnregan cm300003965_557fc578e4b0094eea4f5204 Crash Rate (Mobile)
sdptnregan cm300003965_557fc578e4b0416196926008 Average Session Length (Mobile)
sdptnr-coala-prod cm300003965_557fc656e4b0adadba08f337 Avg. Order Value

Segments

More to come on this topic but keep in mind that segments and calculated metrics are a key part to many of our analysis projects. It would do you well to get really good at understanding segments.

aw_get_segments(expansion = 'definition', limit = 100)
name definition id
Adobe Test1 visitors 53e4e60ee4b0acd00fa0ce9c
Visits from United States hits 53f634a6e4b0acd00fa0eec0
Barneys hits 5516c646e4b060c760327bd2
Neenah Packaging hits 5516d0bce4b060c760327bd4
Senior Manager of Analytics hits 5527eed9e4b060c760329dde
Site Section = blog hits 55551fdbe4b08d109cd584ca
Blog Visitor visitors s300003965_560aa300e4b0ff9bcc064a38
Form Viewers visitors s300003965_560aaa89e4b0298c6791a0b1
Recency - Last 90 days (full Range) visitors s300003965_565e4e0be4b0a1e1c628e8f8
Recency - Last 60 Days visitors s300003965_565e4ff0e4b080610428494c

Requesting Data

Simple Data Request

There is convenient prettynames argument that allows you to ahve report ready column names.

aw_auth('jwt')
#top 5 pages in the last 30 days by visits
df <- aw_freeform_table(dimensions = 'evar1',
                        metrics = 'visits',
                        prettynames = F)
knitr::kable(df)
evar1 visits
/thanks-for-joining-us/ 4480
/ 2300
/ga4-migration-assessment/ 1699
/how-we-help/partners/google/ 1546
/blog/what-is-datorama/ 777
#pretty names
df <- aw_freeform_table(dimensions = 'evar1',
                        metrics = 'visits',
                        prettynames = T)
knitr::kable(df)
Page Path (v1) Visits
/thanks-for-joining-us/ 4480
/ 2300
/ga4-migration-assessment/ 1699
/how-we-help/partners/google/ 1546
/blog/what-is-datorama/ 777

Pulling a Date Range Report

You can choose either ‘daterangehour’, ‘daterangeday’, ‘daterangeweek’, ‘daterangemonth’, ‘daterangequarter’, ‘daterangeyear’

df <- aw_freeform_table(date_range = c(Sys.Date() - 30, Sys.Date() - 1),
                        dimensions = c('daterangeyear',
                                       'daterangequarter',
                                       'daterangemonth', 
                                       'daterangeday',
                                       'daterangehour'),
                        metrics = c("visits"),
                        top = c(1, 1, 2, 0, 0)
)
daterangeyear daterangequarter daterangemonth daterangeday daterangehour visits
2022 Jul 2022 - Sep 2022 Jul 2022 2022-07-31 2022-07-31 23:00:00 10
2022 Jul 2022 - Sep 2022 Jul 2022 2022-07-31 2022-07-31 22:00:00 15
2022 Jul 2022 - Sep 2022 Jul 2022 2022-07-31 2022-07-31 21:00:00 10
2022 Jul 2022 - Sep 2022 Jul 2022 2022-07-31 2022-07-31 20:00:00 17
2022 Jul 2022 - Sep 2022 Jul 2022 2022-07-31 2022-07-31 19:00:00 5
2022 Jul 2022 - Sep 2022 Jul 2022 2022-07-31 2022-07-31 18:00:00 6

Include Calculated Metrics

cm1 <- 'cm300003965_60200cc865d8fb7e012b1db6'

aw_freeform_table(dimensions = 'daterangeday',
                  metrics = cm1,
                  prettynames = T)
Day Page Views / Visit
2022-07-05 1.817877
2022-07-06 1.648107
2022-07-13 1.555678
2022-07-18 1.510309
2022-07-07 1.505708

Multi-Dimensional Data Requests

Unlimited Dimensions is now a thing!

#multilevel dimension
df <- aw_freeform_table(date_range = c('2020-10-01', '2020-10-01'),
                         dimensions = c('daterangeday','page','mobiledevicetype','browser','geocity'),
                         metrics = 'visits',
                         top = c(2))
knitr::kable(df)
daterangeday page mobiledevicetype browser geocity visits
2020-10-01 Engage|Blog Other Google Chrome 85.0 Delhi (Delhi, India) 4
2020-10-01 Engage|Blog Other Google Chrome 85.0 Glencoe (Illinois, United States) 3
2020-10-01 Engage|Blog Other Google Chrome 84.0 Suwanee (Georgia, United States) 1
2020-10-01 Engage|Blog Other Google Chrome 84.0 Stillwater (Minnesota, United States) 1
2020-10-01 Engage|Blog Mobile Phone Safari Portsmouth (New Hampshire, United States) 2
2020-10-01 Engage|Blog Mobile Phone Safari Atlanta (Georgia, United States) 2
2020-10-01 Engage|Blog Mobile Phone Chrome Mobile 85.0 Cebu (Cebu, Philippines) 1
2020-10-01 Engage|Blog Mobile Phone Chrome Mobile 85.0 Brooklyn (New York, United States) 1
2020-10-01 Engage|Search Discovery Education Community Other Google Chrome 85.0 Woodbridge (Virginia, United States) 2
2020-10-01 Engage|Search Discovery Education Community Other Google Chrome 85.0 Madrid (Madrid, Spain) 2
2020-10-01 Engage|Search Discovery Education Community Other Mozilla Firefox 79.0 Bronx (New York, United States) 2
2020-10-01 Engage|Search Discovery Education Community Mobile Phone Safari Suwanee (Georgia, United States) 1
2020-10-01 Engage|Search Discovery Education Community Mobile Phone Safari Scotts Valley (California, United States) 1
2020-10-01 Engage|Search Discovery Education Community Mobile Phone Chrome Mobile 85.0 Gurgaon (Haryana, India) 1
2020-10-01 Engage|Search Discovery Education Community Mobile Phone Chrome Mobile 85.0 Pune (Maharashtra, India) 1

Filter By Segments

#filtering all the segments I pulled earlier
blog <- segs %>% filter(grepl('blog', name)) %>% pull(id)

#segment id added
aw_freeform_table(date_range = c('2020-10-01', '2020-12-31'),
                  dimensions = c('page'),
                  metrics = 'visits',
                  top = 100,
                  ##inlcude the segment id
                  segmentId = blog
)
page visits
About 1
How We Help 1
Terms of Use 1
Engage|Blog 1
How We Help|Technology 1
Stay Current|Events 1
Engage|Blog|Search 1

Search Added

Search argument works for R >v4.0

#segment id added
aw_freeform_table(date_range = c('2020-10-01', '2020-12-31'),
                  dimensions = c('page'),
                  metrics = 'visits',
                  top = 10,
                  search = "(CONTAINS 'blog')"
)
page visits
Engage|Blog 5956
https://www.searchdiscovery.com/blog/google-analytics-app-plus-web 447
Engage|Blog|Search 245
https://www.searchdiscovery.com/blog/creating-checkout-funnel-google-data-studio 168
https://www.searchdiscovery.com/blog/adobe-analytics-new-features 117
https://www.searchdiscovery.com/blog/dynamic-url-parameters-in-adwords 102
https://www.searchdiscovery.com/blog/integrating-onetrust-with-adobe-launch 64
https://www.searchdiscovery.com/blog/bounce-rate-in-google-analytics-4 59
https://www.searchdiscovery.com/blog/what-is-google-analytics-4 58
https://www.searchdiscovery.com/blog/instagram-contest 50

Segment Freeform Table

New Function!

This is the equivalent of a freeform table with segments as the row components. This type of table offers a few components that aw_freeform_table does not. For example, this function does not require (or allow) dimensions to be included in the breakdown. Segment IDs are automatically translated into their human-readable names.

seg1 <- 's300003965_5f89910f2b368719693edf6e'
seg2 <- 's300003965_5eab136b34d05f0ff1c318ff'

aw_segment_table(segmentIds = c(seg1, seg2), metrics = c('visits', 'pageviews'))
name id visits pageviews
Careers Site Section Hits s300003965_5f89910f2b368719693edf6e 570 834
Blog Views s300003965_5eab136b34d05f0ff1c318ff 5383 6522

Building Segments

New Function Introduction Junction

Verbs

This data function will return a list of all available verbs for building segments. They are divided up into 3 different categories: ‘Exists’, ‘Strings’, and ‘Numbers’. You can determine what category of verb to use by the object you are going to be using. For instance, if the object is going to be a number then the verb must be a number verb.

seg_verbs
type class verb description
string string streq Equals
string string not-streq Not Equals
string string strlt Less Than
string string strgt Greater Than
string string strle Less Than or Equals
string string strge Greater Than or Equals
string list streq-in Match a string to any of the values in the parameter
string list not-streq-in Ensure a string doesn’t match any of the values in the parameter
string string contains Ensure a string matches or contains the value in the parameter
string string not-contains Ensure a string doesn’t match or contains the value in the parameter
string list contains-any-of Ensure a string contains any of the values in the parameter. Case-insensitive.
string list contains-all-of Ensure a string contains all of the values in the parameter. Case-insensitive.
string list not-contains-any-of Ensure a string doesn’t contain at least one of the values in the parameter. Case-insensitive.
string list not-contains-all-of Ensure a string doesn’t contain any of the values in the parameter. Case-insensitive.
string string starts-with Ensure a string starts with the value in the parameter. Case-insensitive.
string string ends-with Ensure a string ends with the value in the parameter. Case-insensitive.
string string not-starts-with Ensure a string doesn’t start with the value in the parameter. Case-insensitive.
string string not-ends-with Ensure a string doesn’t end with the value in the parameter. Case-insensitive.
string glob matches Ensure a string matches the glob parameter. A glob parameter uses a ’’ character to match any sequence of characters. A literal ’’ is expressed with ’*’.
string glob not-matches Ensure a string doesn’t match the glob parameter. A glob parameter uses a ’’ character to match any sequence of characters. A literal ’’ is expressed with ’*’.
number number eq Equals
number number not-eq Not equals
number number gt Greater than
number number lt Less than
number number ge Greater than or equal to
number number le Less than
number list eq-any-of Equal to any of the values provided
number list not-eq-any-of Not equal to any of the values provided
number list eq-in Equal to any of the values provided
number list not-eq-in Not equal to any of the values provided
string exists exists Tests if an attribute has been set to a value.
string exists not-exists Tests if an attribute has never been set to a value.
number exists event-exists Tests if an attribute has been set to a number value.
number exists not-event-exists Tests if an attribute has never been set to a number value.

New Functions

  1. seg_rule() - This function creates the simple rule of a segment.

    seg_rule(dimension or metric, verb, object)

  2. seg_then() - This function creates a then list object which restricts the time constraint of a segment to be added to a sequence segment.

    seg_then(limit = "within", count = 1, unit = "year")

  3. seg_con() - This function combines rules into a container.

    seg_con(context = "hits", conjunction = "and", rules = NULL, exclude = FALSE)

  4. seg_seq() - This function combines rules into a sequence container.

    seg_seq(context = "visits", rules = NULL, sequence = "in_order")

  5. seg_build() - This function combines rules, containers and/or sequences into a single JSON string and can then make the post call to create the segment in Adobe Analytics or return the json string for use in other api calls or for validation.

    seg_build(name, description, rules, context = "hits", conjunction = "and", create_seg = FALSE)

  6. seg_val() - Returns a segment validation response for a segment contained in a json string object.

    seg_val(segment_body)

Basic Segment Example

aw_auth('jwt')
Successfully authenticated with JWT: access token valid until 2022-08-02 14:26:03
rule1 = seg_rule(dimension = 'daterangehour', 
                 verb = 'eq', 
                 object = c('2021-11-02', '1600'))
rule2 = seg_rule(dimension = 'page', 
                 verb = 'contains', 
                 object = 'home')
built <- seg_build('Basic Segment For My Test',
                   'This was created by Ben Woodard as a test',
                   conjunction = 'and',
                   rules = list(rule1, rule2),
                   context = 'visitors')
seg_val(built)
[1] "The segment is valid."

Adding containers to build the segment

rule1 = seg_rule(dimension = 'daterangehour', 
                 verb = 'eq', 
                 object = c('2021-11-02', '1600'))
rule2 = seg_rule(dimension = 'page', 
                 verb = 'contains', 
                 object = 'home', 
                 description = 'something')
rule3 = seg_rule(metric = 'visits', 
                 verb = 'exists')
con1 = seg_con(context = 'hits',
               conjunction = 'or',
               rules = list(seg_rule(dimension = 'page', 
                 verb = 'contains', 
                 object = 'home', 
                 description = 'something'), rule3))
built <- seg_build('This is a Basic combined Segment For My Test',
                   'This was created by Ben Woodard as a test',
                   conjunction = 'and',
                   containers = list(rule1, con1),
                   context = 'visits',
                   create_seg = F)
seg_val(built)

Non-repeating Instance and Repeating Instance

rule1 <- seg_rule(dimension = 'page', 
                  verb = 'streq', 
                  object = 'Home', 
                  attribution = 'repeating') #default
rule2 <- seg_rule(dimension = 'page', 
                  verb = 'streq', 
                  object = 'Home', 
                  attribution = 'nonrepeating', 
                  attribution_context = 'visits')
rule3 <- seg_rule(dimension = 'visitnumber', 
                  verb = 'eq', 
                  object = 1, 
                  attribution = 'instance')
built <- seg_build(name = 'Instance and Non-Repeating Instance example',
          description = 'This is the example of the repeating and non-repeating instance',
          rules = list(rule1, rule2, rule3), 
          context = 'hits',
          conjunction = 'or',
          create_seg = F)
seg_val(built)

Count Distinct Dimension Segment

rule1 <- seg_rule(dimension = 'page',
                  is_distinct = TRUE,
                  verb = 'ge', #using number verb because the count distinct argument is true
                  object = 5)
built <- seg_build(name = "Count Distinct Segment",
                   description = "Unique Counts",
                   context = 'visitors',
                   rules = list(rule1) )
seg_val(built)

Excluding Containers in a segment

#create the rule to define the page view
rule <- seg_rule(dimension = 'page',
                      verb = 'streq',
                      object = 'Home')
#create the 2 page view limite per visitor
con2 <- seg_seq(context = 'visitors',
                rules = list(rule, rule), 
                sequence = 'in_order') #this uses the conjunction 'then'
#create the container including either visitors with 1 or 2 pageviews
con2_in <- seg_con(context = 'visitors',
                   conjunction = 'or',
                   rules = list(rule, con2))
#create the container exclude visitors with 3 pageviews (would automatically exclude more than 3 because they had 3 if they had 4.)
con3_x <- seg_seq(context = 'visitors', 
                  rules = list(rule, rule, rule), 
                  sequence = 'in_order',
                  exclude = TRUE) 
#create the segment in Adobe 
built <- seg_build(name = "Exclude 2 Home Pageview Visitors",
                   description = "Written as an example",
                   context = 'visitors',
                   rules = list(con2_in, con3_x), 
                   conjunction = 'and')
seg_val(built)

Sequence Segments

Basic Sequence

rule1 <- seg_rule(dimension = 'daterangeday',
                  verb = 'eq',
                  object = '2021-09-13')

rule2 <- seg_rule(dimension = 'page',
                  verb = 'contains',
                  object = 'blog')

built <- seg_build('Visited on 9/13 and then visited the blog',
                     'This was created by Ben Woodard as a test',
                     sequences = list(rule1, rule2),
                     sequence = 'in_order',
                     context = 'visitors')

seg_val(built)

Basic Context Change Sequence

rule1 <- seg_rule(dimension = 'daterangeday',
                  verb = 'eq',
                  object = '2021-09-13')
then <- seg_then(limit = 'after', count = 2, unit = 'hit')
rule2 <- seg_rule(dimension = 'page',
                  verb = 'contains',
                  object = 'blog')
built <- seg_build('Visited on 9/13 and then after 2 hits visited the blog',
                   'This was created by Ben Woodard as a test',
                   sequences = list(rule1, then, rule2),
                   sequence_context = 'visits', 
                   sequence = 'in_order',
                   context = 'visitors')
seg_val(built)

Time Restriction (then) Sequence

Adding a time restriction using the seg_then() function

In the UI there is a clock after the “then” term. when clicked there are 2 options that are shown: after and while. You can choose any of the different

rule1 <- seg_rule(dimension = 'daterangeday',
         verb = 'eq',
         object = '2021-09-13')
thenit <- seg_then('after', 1, 'hit')

rule2 <- seg_rule(dimension = 'page',
                  verb = 'contains',
                  object = 'blog')
sequ <- seg_seq(context = 'visits', 
                rules = list(rule1, thenit, rule2))
built <- seg_build('Visited on 9/13 and then visited the blog',
                     'This was created by Ben Woodard as a test',
                     containers = list(sequ),
                     context = 'visits',
                   sequence_context = 'visitors')
seg_val(built)

Within + After Time Restriction Sequence

You can also add the ‘after’ and ‘within’ time restrictions together just like in the UI. The function will automatically put the proper one first but you still want to be cognizant of the time restriction you are placing on your function.

red1 <- seg_rule(dimension = 'daterangeday',
                 verb = 'eq',
                 object = '2021-09-13')
thenit <- seg_then(limit = c('within', 'after'), 
                  count = c(1, 2),
                  unit = c('week', 'visit')) #unit is always singular
rule2 <- seg_rule(dimension = 'page',
                  verb = 'exists')
sequ <- seg_seq(context = 'visits', 
                rules = list(red1, thenit, rule2))
built <- seg_build('Compound then statement',
                     'This was created by Ben Woodard as a test',
                     containers = list(sequ),
                     context = 'visitors')
seg_val(built)

Within + After Time Restriction & Standard Container

This segment will combine the sequence container and basic container into a segment.

rule1 <- seg_rule(dimension = 'page',
                 verb = 'streq',
                 object = 'Home')
thenit <- seg_then(limit = c('after', 'within'), 
                  count = c(1, 1),
                  unit = c('hit', 'visit')) #unit is always singular
rule2 <- seg_rule(dimension = 'page',
                  verb = 'contains',
                  object = 'Blog')
rule3 <- seg_rule(dimension = 'visitnumber',
                  verb = 'eq',
                  object = 4)
rule4 <- seg_rule(dimension = 'page',
                  verb = 'exists')
## make the different containers (sequence container and basic container)
sequ1 <- seg_seq(context = 'visits', 
                 rules = list(rule1, thenit, rule2, rule1))
con2 <- seg_con(context = 'hits', 
                rules = list(rule3, rule4))
built <- seg_build(name = 'Compound then statement',
                   description = 'This was created by Ben Woodard as a test',
                   context = 'visitors',
                   sequence_context = 'visits',
                   sequences  = list(sequ1, con2))
seg_val(built)

Inline Segment Building

## The basic flow of these objects can be looked at in this way.
built <- seg_build(name = 'Compound then statement',
                   description = 'This was created by Ben Woodard as a test',
                   context = 'visitors',
                   sequence_context = 'visits',
                   sequences  = list(seg_seq(context = 'visits', 
                                             rules = list(seg_rule(dimension = 'page',verb = 'streq',object = 'Home'), 
                                                               seg_then(limit = c('after', 'within'), count = c(1, 1), unit = c('hit', 'visit')), 
                                                               seg_rule(dimension = 'page', verb = 'contains', object = 'Blog'), 
                                                               seg_rule(dimension = 'page',verb = 'streq',object = 'Home'))), 
                                     seg_con(context = 'hits', 
                                             rules = list(seg_rule(dimension = 'visitnumber', verb = 'eq', object = 4), 
                                                                seg_rule(dimension = 'page', verb = 'exists')))) )

In Order, Before, and After Sequence

Sequence prefix and suffix will enable the user to define if the segment should only include those after or before the sequence of events.

rule1 <- seg_rule(dimension = 'page',
                 verb = 'streq',
                 object = 'Home')
thenit <- seg_then(limit = c('after', 'within'), 
                  count = c(1, 1),
                  unit = c('hit', 'visit')) #unit is always singular
rule2 <- seg_rule(dimension = 'page',
                  verb = 'contains',
                  object = 'Blog')
rule3 <- seg_rule(dimension = 'visitnumber',
                  verb = 'eq',
                  object = 4)
rule4 <- seg_rule(dimension = 'page',
                  verb = 'exists')
## make the different containers (sequence container and basic container)
sequ1 <- seg_seq(context = 'visitors', 
                rules = list(rule1, thenit, rule2),
                sequence = 'before') ## adding the sequence to include only visitors before
con2 <- seg_con(context = 'hits', 
                rules = list(rule3, rule4))
built <- seg_build('Using the sequence Before',
                     'This was created by Ben Woodard as a test',
                     sequences  = list(sequ1, con2),
                     sequence_context = 'visits',
                     sequence = 'after', ##Include only those visits after the sequence
                     context = 'visitors')
seg_val(built)

Exclude checkpoints in a sequence

rule1 <- seg_rule(dimension = 'page',
                  verb = 'streq',
                  object = 'Home')
rule2 <- seg_rule(dimension = 'page',
                  verb = 'contains',
                  object = 'blog')
rule3 <- seg_rule(dimension = 'visitnumber',
                  verb = 'gt',
                  object = 3)
seq1 <- seg_seq(context = 'visits',
                rules = list(rule1, rule2, rule3),
                sequence = 'in_order',
                exclude = F,
                exclude_checkpoint = 2)
built <- seg_build(name = 'Exclude a checkpoint in a sequence',
                   description = 'defined checkpoint 2 to be excluded from the sequence',
                   containers = list(seq1), 
                   context = 'visits')
seg_val(built)

cjar

Just Published on March 3, 2022

cjar Downloads

Authentication

Very similar to adobeanalyticsr in a lot of ways. One catch, only JWT authentication is available at this time.

library(cjar)
cjar::cja_auth('jwt')
Successfully authenticated with JWT: access token valid until 2022-08-02 14:26:09

Key Differences

Metric IDs Are Long

The IDs for metrics and dimensions are a lot longer than what we are familiar with in Adobe Analytics.

mets <- cja_get_metrics()
knitr::kable(
head(mets$id)
)
x
productListItems._experience.analytics.event601to700.event616.value
productListItems._experience.analytics.event901to1000.event953.value
_experience.analytics.event601to700.event678.value
_experience.analytics.event201to300.event229.value
_experience.analytics.event1to100.event9.value
_experience.analytics.event501to600.event549.value

Dataviews Instead Of Report Suites

dvs <- cja_get_dataviews()
knitr::kable(
head(dvs)
)
name id systemUserOwned
ForgeDX IdeaCloud dv_5f244913c5e4fb0e66545d73 NA
Demo System Data View dv_5f31a113e2bc180e66186089 NA
Combined CJA Lab Action bgeorge dv_5f3cabee5788290e6707196e NA
Stoke Salesforce Integration Demo v1 dv_5f3e6cddeaf4860e6a8b4b1b NA
Stoke Salesforce Integration Demo v2 dv_5f3ed4e98e7ce20e65688253 NA
Google Analytics Demo Data View dv_5f4f1e2572ea4e09073ce262 NA

Filters Instead of Segments

filters <- cja_get_filters()
knitr::kable(
head(filters)
)
name description organization id owner dataId
GA: Not New People EDA8E66E593730510A495EFA@AdobeOrg sEDA8E66E593730510A495EFA@AdobeOrg_5f89ceea63f04c09def28a9d C6B17ECB62DD8D840A495FD1@b9bf09c062dd315c495e9d.e NA
Unique EDA8E66E593730510A495EFA@AdobeOrg sEDA8E66E593730510A495EFA@AdobeOrg_5f89ceeaede7f509dec1d0e8 CE73768462DD8D8F0A495E5F@b9bf09c062dd315c495e9d.e NA
Single Page Sessions EDA8E66E593730510A495EFA@AdobeOrg sEDA8E66E593730510A495EFA@AdobeOrg_5f89ceed63f04c09def28a9e C6B17ECB62DD8D840A495FD1@b9bf09c062dd315c495e9d.e NA
Single Touch EDA8E66E593730510A495EFA@AdobeOrg sEDA8E66E593730510A495EFA@AdobeOrg_5f89ceeed08dac09dffc8dfe C6B17ECB62DD8D840A495FD1@b9bf09c062dd315c495e9d.e NA
New Sessions EDA8E66E593730510A495EFA@AdobeOrg sEDA8E66E593730510A495EFA@AdobeOrg_5f89ceeeede7f509dec1d0e9 C6B17ECB62DD8D840A495FD1@b9bf09c062dd315c495e9d.e NA
Two Touch EDA8E66E593730510A495EFA@AdobeOrg sEDA8E66E593730510A495EFA@AdobeOrg_5f89ceeeede7f509dec1d0ea C6B17ECB62DD8D840A495FD1@b9bf09c062dd315c495e9d.e NA

Wrap Up

Current Use Case Examples

  1. Automated Adobe Analytics Big Query + Data Studio Data Flow

    • As the cool kids say “AAABQ+DSDF”
    • There was a data flow setup sending data from AA (old API) > Domo > Google Sheets (via appscript) > Data Studio
    • The new Big Query integration with DS takes about 5 seconds to load vs 90+ seconds with Sheets
  2. 1,506 Rule Segment Build

    • Needed to define a segment using 1,506 different rules
    • The Adobe system choked on the number of rules but it did validate and was trying to run
    • Discovered “contains any” along the way but the limit is 500 unique items.
  3. Code First Segment Definitions and Maintenance for Reporting

    • Built 13 different complex segments for an HVA Analysis
    • Found out we were missing an exclusion rule
    • Created the exclusion rule, applied the object to the existing definitions
    • Reran the code to rebuild the segments
    • Less than 15 minutes
    • Delivered transparent segment definitions to the client in the report

What’s Next?

  1. Projects
- The projects endpoint was just release publicly
- Apollo has been dynamically creating projects via the API for over a year
- Pull a project from an existing account, make edits to the dimensions, metrics, color scheme, and push it live in a brand new account.
  1. Annotations
- Announced during Adobe Summit this year
- API was released about 2 months ago
- Compile information around annotations that are missing from the reports, format a spreadsheet of annotations and then push list to report suite
  1. Calculated Metrics
- Create a series of functions to build Calculated Metrics using code
- Similar to Segment building functions in their modularity and defining capabilities
  1. Segments as Global Filter
- There is a way to add a segment to the freeform table using the definition
- This would alleviate the issue with having to create segments first and possibly overburdening the system with many duplicate segments.

Questions?