[webinar] a non-coders guide to adwords scripts
TRANSCRIPT
@ChristiJOlson @SamuelDJames#PI_Scripts #AdWordsScripts
A Non-Coders Guide to Adwords ScriptsIt’s not as intimidating as you thought!
Point It Digital Marketingwww.Pointit.com 06.17.2015
@ChristiJOlson @SamuelDJames#PI_Scripts #AdWordsScripts
Housekeeping Slide
Additional Q&A addressed and at the end of session
A link to view a recorded version of the webinar will be emailed within 48 hours
Raise your hand if you are having technical difficulties
Hide the chat window
Submit question via chat
Toolbox Blog on the Point It Website
@ChristiJOlson @SamuelDJames#PI_Scripts #AdWordsScripts
#PI_Scripts#AdWordsScripts
@ChristiJOlson @SamuelDJames
@ChristiJOlson @SamuelDJames#PI_Scripts #AdWordsScripts
About Point It
Our Clients
Our Services
@ChristiJOlson @SamuelDJames#PI_Scripts #AdWordsScripts
Today’s Presenters
5
Christi OlsonPoint It Digital MarketingDirector of SEM
Samuel D. JamesPoint It Digital MarketingDirector of Analytics
@ChristiJOlson @SamuelDJames#PI_Scripts #AdWordsScripts
STRUCTURE BASIC CONCEPTSREADING SCRIPTSEDITING SCRIPTS
WHAT WE’LL BE TALKING ABOUT TODAY:
@ChristiJOlson @SamuelDJames#PI_Scripts #AdWordsScripts
IS LIKE LEARNING A NEW LANGUAGE…
STRUCTURE TERMINOLOGY
BASIC RULES
PRACTICE MAKES PERFECT
@ChristiJOlson @SamuelDJames#PI_Scripts #AdWordsScripts
SCRIPTS ENABLE YOU TO AUTOMATE ALL THE THINGS
THAT CAN BE DONE MANUALLY IN ADWORDS
@ChristiJOlson @SamuelDJames#PI_Scripts #AdWordsScripts
SCRIPTS CANMAKE CHANGES TO OR REPORT ON
ANY ELEMENT OF AN ADWORDS ACCOUNT.
ACCOUNT OR MCC LEVEL
@ChristiJOlson @SamuelDJames#PI_Scripts #AdWordsScripts
ANYTHING YOU CAN DO SCRIPTS CAN DO TOO
“Annie Get Your Gun”
@ChristiJOlson @SamuelDJames#PI_Scripts #AdWordsScripts
SO WHY ARE SO MANY MARKETERS INTIMIDATED
BY SCRIPTS?
@ChristiJOlson @SamuelDJames#PI_Scripts #AdWordsScripts
THEUNKNOWN
IS JAVASCRIPT.
IT’S NOT PART OF THE AVERAGE SEM SKILL SET.
@ChristiJOlson @SamuelDJames#PI_Scripts #AdWordsScripts
@ChristiJOlson @SamuelDJames#PI_Scripts #AdWordsScripts
@ChristiJOlson @SamuelDJames#PI_Scripts #AdWordsScripts
LET'S START WITH
STRUCTURE
@ChristiJOlson @SamuelDJames#PI_Scripts #AdWordsScripts
I LIKE COOKING MY FAMILY AND PETS
@ChristiJOlson @SamuelDJames#PI_Scripts #AdWordsScripts
I LIKE COOKING, MY FAMILY, AND PETS.
USE PROPER STYLE [PUNCTUATION]THE LIVES IT SAVES MIGHT BE YOUR FAMILY'S
Google JavaScript Coding Style Guide:
bit.ly/GoogleJavaScript
@ChristiJOlson @SamuelDJames#PI_Scripts #AdWordsScripts
NOTEPAD++ bit.ly/Notepad-plusplus
• OUTLINES CODE
• MAKES IT EASIER TO SEE WHAT YOU ARE DOING
@ChristiJOlson @SamuelDJames#PI_Scripts #AdWordsScripts
SCRIPTS ARE CASE SENSITIVE AND
NEED TO BE WRITTEN IN camelCase
@ChristiJOlson @SamuelDJames#PI_Scripts #AdWordsScripts
// IS A SINGLE COMMENT LINE
// comments can start anywhere in a line and javascript will skip to the end of the line// add as many or as few comments to your code explaining what it does
(DOUBLE SLASH)
@ChristiJOlson @SamuelDJames#PI_Scripts #AdWordsScripts
/* SINGLE FORWARD SLASH + ASTERISK
(SLASH)
*Signifies comments that span multiple*lines. *Multiline comments end with */
@ChristiJOlson @SamuelDJames#PI_Scripts #AdWordsScripts
ALWAYS PREVIEW
A SCRIPT BEFORE YOU RUN IT
@ChristiJOlson @SamuelDJames#PI_Scripts #AdWordsScripts@ChristiJOlson @SamuelDJames
LET'S MOVE TO THE
BASIC CONCEPTS
@ChristiJOlson @SamuelDJames#PI_Scripts #AdWordsScripts
THE KEY ITEMS YOU NEED TO KNOW:
• FUNCTIONS• OBJECTS (ELEMENTS)• ENTITIES• VARIABLES• METHODS• SELECTORS• ITERATORS
@ChristiJOlson @SamuelDJames#PI_Scripts #AdWordsScripts
function main() {var keywords = AdWordsApp.keywords().withCondition(“Status = ‘ENABLED’”)
.orderBy("Impressions DESC")
.forDateRange("YESTERDAY")
.withLimit(10)
.get();
Logger.log("10 keywords with most impressions yesterday");while (keywords.hasNext()) {var keyword = keywords.next();Logger.log(keyword.getText() + ": " +
keyword.getStatsFor("YESTERDAY").getImpressions());}
}
ANATOMY OF A BASIC SCRIPT
FUNCTION
SELECTORS
ITERATOR + next METHODS
VARIABLE, OBJECT, ENTITY
LOGGER
METHODS
@ChristiJOlson @SamuelDJames#PI_Scripts #AdWordsScripts
FUNCTIONS PERFORM TASKS / PROCEDURES
{ } CURLY BRACKETS DEFINE THE BEGINNING & END OF A
FUNCTION
@ChristiJOlson @SamuelDJames#PI_Scripts #AdWordsScripts
OBJECTS -- COLLECTION OF “ENTITIES”
AdWordsApp MccApp
SpreadsheetApp UrlFetchApp
ADWORDSACCOUNT
CONNECTS WITH SPREADSHEETS
(FOR REPORTING)
ACROSS YOUR MCC
COMMUNICATES WITH OTHER SERVICES &
APPLICATIONS
@ChristiJOlson @SamuelDJames#PI_Scripts #AdWordsScripts
ENTITIES – ELEMENT OR PROPERTY
List of AdWords Entities:
bit.ly/1aeDxby
@ChristiJOlson @SamuelDJames#PI_Scripts #AdWordsScripts
VARIABLES (VAR) ARE USED TO NAME & STORE DATA WITHIN YOUR SCRIPTS
variables are like a container to store “data”
@ChristiJOlson @SamuelDJames#PI_Scripts #AdWordsScripts
ESTABLISH YOUR OBJECTAND SELECT AN ENTITY TO QUERY
var keywords = AdWordsApp.keywords()
OBJECTNAMED
VARIABLE ENTITY
JOIN AN OBJECT AND ENTITY WITH A PERIOD
@ChristiJOlson @SamuelDJames#PI_Scripts #AdWordsScripts
METHODS ARE HOW SCRIPTS INTERACT WITH OBJECTS
• RETRIEVE INFORMATION ABOUT AN OBJECT (WHAT IT IS)
• ASK AN OBJECT ABOUT ITSELF (WHAT CAMPAIGN A KWD IS IN)
• TELL THE OBJECT TO DO SOMETHING (CHANGE STATUS)
@ChristiJOlson @SamuelDJames#PI_Scripts #AdWordsScripts
EXAMPLES OF METHODS
get()getQualityScore()
setDestinationURL()WHEN SETTING OR SPECIFYING A VALUES ENTER IT BETWEEN THE BRACKETS ()
SOME METHODS REQUIRE VALUES. MOST ARE LEFT BLANK ()
@ChristiJOlson @SamuelDJames#PI_Scripts #AdWordsScripts
SELECTORS REFINE THE LIST OF ENTITIES
•withCondition()
•withIds()•forDateRange()•withLimit()•orderBy()
@ChristiJOlson @SamuelDJames#PI_Scripts #AdWordsScripts
SELECTORS REFINE THE LIST OF ENTITIES AND CAN ORDER IT
• withCondition()(‘Entity > N’); Greater than(‘Entity <N’); Less than
•forDateRange()forDateRange(‘YESTERDAY’); forDateRange(‘LAST_14_DAYS’);
•orderBy()(‘Entity ASC’); Ascending Order (‘Entity DESC’); Descending Order
@ChristiJOlson @SamuelDJames#PI_Scripts #AdWordsScripts
ITERATORS RETURN THE NEXT ITEM
• ITERATORS ARE LIKE AN ARRAY• PATTERN BASED SEARCH• COME AFTER SELECTORS
hasNext()objectNext()
@ChristiJOlson @SamuelDJames#PI_Scripts #AdWordsScripts
LOGGER OUTPUTS THE DATA TO A PREVIEW PANEL
• HELP TROUBLESHOOT SCRIPTS
• SLOWS PROCESSING TIME• RECOMMEND REMOVING
AFTER DEBUGGING
@ChristiJOlson @SamuelDJames#PI_Scripts #AdWordsScripts
LET'S TIE IT TOGETHER
READING SCRIPTS
@ChristiJOlson @SamuelDJames#PI_Scripts #AdWordsScripts
ANATOMY OF A BASIC SCRIPT
function main() {var keywords = AdWordsApp.keywords().withCondition(“Status = ‘ENABLED’”)
.orderBy("Impressions DESC")
.forDateRange("YESTERDAY")
.withLimit(10)
.get();
Logger.log("10 keywords with most impressions yesterday");while (keywords.hasNext()) {var keyword = keywords.next();Logger.log(keyword.getText() + ": " +
keyword.getStatsFor("YESTERDAY").getImpressions());}
}
@ChristiJOlson @SamuelDJames#PI_Scripts #AdWordsScripts
function main() {var keywords = AdWordsApp.keywords().withCondition(“Status = ‘ENABLED’”)
.orderBy("Impressions DESC")
.forDateRange("YESTERDAY")
.withLimit(10)
.get();
Logger.log("10 keywords with most impressions yesterday");while (keywords.hasNext()) {var keyword = keywords.next();Logger.log(keyword.getText() + ": " +
keyword.getStatsFor("YESTERDAY").getImpressions());}
}
FUNCTION starts the script
ANATOMY OF A BASIC SCRIPT
@ChristiJOlson @SamuelDJames#PI_Scripts #AdWordsScripts
function main() {var keywords = AdWordsApp.keywords().withCondition(“Status = ‘ENABLED’”)
.orderBy("Impressions DESC")
.forDateRange("YESTERDAY")
.withLimit(10)
.get();
Logger.log("10 keywords with most impressions yesterday");while (keywords.hasNext()) {var keyword = keywords.next();Logger.log(keyword.getText() + ": " +
keyword.getStatsFor("YESTERDAY").getImpressions());}
}
VARIABLE named keywordsOBJECT ENTITY
ANATOMY OF A BASIC SCRIPT
@ChristiJOlson @SamuelDJames#PI_Scripts #AdWordsScripts
function main() {var keywords = AdWordsApp.keywords().withCondition(“Status = ‘ENABLED’”)
.orderBy("Impressions DESC")
.forDateRange("YESTERDAY")
.withLimit(10)
.get();
Logger.log("10 keywords with most impressions yesterday");while (keywords.hasNext()) {var keyword = keywords.next();Logger.log(keyword.getText() + ": " +
keyword.getStatsFor("YESTERDAY").getImpressions());}
}
SELECTORS find keywords:• Enabled• Descending Order by Impression• Date = Yesterday• First 10 (by impression)
ANATOMY OF A BASIC SCRIPT
@ChristiJOlson @SamuelDJames#PI_Scripts #AdWordsScripts
function main() {var keywords = AdWordsApp.keywords().withCondition(“Status = ‘ENABLED’”)
.orderBy("Impressions DESC")
.forDateRange("YESTERDAY")
.withLimit(10)
.get();
Logger.log("10 keywords with most impressions yesterday");while (keywords.hasNext()) {var keyword = keywords.next();Logger.log(keyword.getText() + ": " +
keyword.getStatsFor("YESTERDAY").getImpressions());}
}
METHODS gets keywords
ANATOMY OF A BASIC SCRIPT
@ChristiJOlson @SamuelDJames#PI_Scripts #AdWordsScripts
function main() {var keywords = AdWordsApp.keywords().withCondition(“Status = ‘ENABLED’”)
.orderBy("Impressions DESC")
.forDateRange("YESTERDAY")
.withLimit(10)
.get();
Logger.log("10 keywords with most impressions yesterday");while (keywords.hasNext()) {var keyword = keywords.next();Logger.log(keyword.getText() + ": " +
keyword.getStatsFor("YESTERDAY").getImpressions());}
}
ITERATOR + next METHODS
ANATOMY OF A BASIC SCRIPT
@ChristiJOlson @SamuelDJames#PI_Scripts #AdWordsScripts
function main() {var keywords = AdWordsApp.keywords().withCondition(“Status = ‘ENABLED’”)
.orderBy("Impressions DESC")
.forDateRange("YESTERDAY")
.withLimit(10)
.get();
Logger.log("10 keywords with most impressions yesterday");while (keywords.hasNext()) {var keyword = keywords.next();Logger.log(keyword.getText() + ": " +
keyword.getStatsFor("YESTERDAY").getImpressions());}
}
LOGGER outputs the data for preview
ANATOMY OF A BASIC SCRIPT
@ChristiJOlson @SamuelDJames#PI_Scripts #AdWordsScripts
function main() {var keywords = AdWordsApp.keywords().withCondition(“Status = ‘ENABLED’”)
.orderBy("Impressions DESC")
.forDateRange("YESTERDAY")
.withLimit(10)
.get();
Logger.log("10 keywords with most impressions yesterday");while (keywords.hasNext()) {var keyword = keywords.next();Logger.log(keyword.getText() + ": " +
keyword.getStatsFor("YESTERDAY").getImpressions());}
}
closes out the functioncloses out the iterator
ANATOMY OF A BASIC SCRIPT
@ChristiJOlson @SamuelDJames#PI_Scripts #AdWordsScripts
function main() {var keywords = AdWordsApp.keywords().withCondition(“Status = ‘ENABLED’”)
.orderBy("Impressions DESC")
.forDateRange("YESTERDAY")
.withLimit(10)
.get();
Logger.log("10 keywords with most impressions yesterday");while (keywords.hasNext()) {var keyword = keywords.next();Logger.log(keyword.getText() + ": " +
keyword.getStatsFor("YESTERDAY").getImpressions());}
}
ANATOMY OF A BASIC SCRIPT
closes out the function
FUNCTION starts the script
closes out the iterator
SELECTORS find keywords:• Enabled• Descending Order by Impression• Date = Yesterday• First 10 (by impression)
ITERATOR + next METHODS
VARIABLE ties ENTITY & OBJECT together
LOGGER
METHODS gets keywords
@ChristiJOlson @SamuelDJames#PI_Scripts #AdWordsScripts
GET STARTED NOW WITH
PRE-WRITTEN SCRIPTS
@ChristiJOlson @SamuelDJames#PI_Scripts #AdWordsScripts
Adwords Developer Script Solutions
bit.ly/ScriptSolutions
@ChristiJOlson @SamuelDJames#PI_Scripts #AdWordsScripts
SCRIPTS YOU CAN USE NOW:
• Campaign & Keyword Performance Report, Written by Russ Savage
• Quality Score Tracker, Written by Martin Roettgerding
• Keyword Performance by QS & Position, Written by Google Developers
• Anomaly Detector, Written by Google Developers
• Broken URL Checker, Written by Google Developers & Russ Savage (FreeAdwordsScripts.com)
• Account Audit, Written by Russ Savage (FreeAdwordsScripts.com)
• Search Query Manager, Written by Marcela De Vivo (Gryffin.com)
Toolbox Blog on the Point It Website
@ChristiJOlson @SamuelDJames#PI_Scripts #AdWordsScripts
RESOURCES AND PEOPLE TO FOLLOW:
Optmyzr.com FreeAdwordsScripts.com
@RussellSavage@SiliconVaelleys@ArmondHammer@BloomArty
@ChristiJOlson @SamuelDJames#PI_Scripts #AdWordsScripts
LET'S GET COMFORTABLE WITH
EDITING SCRIPTS
@ChristiJOlson @SamuelDJames#PI_Scripts #AdWordsScripts
STARTED W/ KEYWORD PERFORMANCE REPORT
Wanted to add 2 additional data points:• Converted Clicks (CVR, CPA)• Conversion Value (ROAS)
@ChristiJOlson @SamuelDJames#PI_Scripts #AdWordsScripts
EXISTINGS SCRIPT: KWD PERFORMANCE REPORT
bit.ly/GG-QSkwdScript
@ChristiJOlson @SamuelDJames#PI_Scripts #AdWordsScripts
DON’T FORGET TO UPDATE THE EMAIL/URL (VAR)
• RECIPIENT_EMAIL• your email address
• SPREADSHEET_URL• URL for the Google Spreadsheet
// Comma-separated list of recipients. Comment out to not send any emails.var RECIPIENT_EMAIL = '[email protected]';
// URL of the default spreadsheet template. This should be a copy of http://goo.gl/cULxUXvar SPREADSHEET_URL = 'https://docs.google.com/spreadsheet/ccc?key=abc123#gid=0';
@ChristiJOlson @SamuelDJames#PI_Scripts #AdWordsScripts
GOAL: ADD ADDITIONAL DATA POINTS
Wanted to add 2 additional data points:Converted Clicks (CVR, CPA)• Conversion Value (ROAS)
stats.getConvertedClicks() workedstats.getConversionValue() kept giving me an error
getConversionValue() is not available with statsit has to be pulled via a separate type of report
@ChristiJOlson @SamuelDJames#PI_Scripts #AdWordsScripts
THE OUTPUT WITH CONVERTED CLICKS
Wanted to add 2 additional data points:• Converted Clicks (CVR, CPA)• Conversion Value (ROAS)
@ChristiJOlson @SamuelDJames#PI_Scripts #AdWordsScripts
KEYWORD PERFORMANCE REPORT
Added to the additional columns to Headers
function outputQualityScoreData(sheet) {// Output header rowvar header = ['Quality Score','Num Keywords','Impressions','Clicks','CTR (%)','Cost','ConvertedClicks',
];sheet.getRange(3, 2, 1, 7).setValues([header]);
This is an ARRAY In this context it let you update specific data within a spreadsheet. You’re telling it where!getRange = (row to start on,
column to start on, number of rows to include,number of columns to include)
@ChristiJOlson @SamuelDJames#PI_Scripts #AdWordsScripts
KEYWORD PERFORMANCE REPORT
Added to the additional columns to Headers
function outputQualityScoreData(sheet) {// Output header rowvar header = ['Quality Score','Num Keywords','Impressions','Clicks','CTR (%)','Cost','ConvertedClicks',
];sheet.getRange(3, 2, 1, 7).setValues([header]);
I added 1 columnsIncrease # of columns from 6 to 7
Check for multiple instances of arrays within the script!
@ChristiJOlson @SamuelDJames#PI_Scripts #AdWordsScripts
KEYWORD PERFORMANCE REPORT
Added to the additional getStats()
// Compute datavar keywordIterator = AdWordsApp.keywords()
.forDateRange('LAST_WEEK')
.withCondition('Impressions > 0')
.get();while (keywordIterator.hasNext()) {var keyword = keywordIterator.next();var stats = keyword.getStatsFor('LAST_WEEK');var data = qualityScoreMap[keyword.getQualityScore()];if (data) {data.numKeywords++;data.totalImpressions += stats.getImpressions();data.totalClicks += stats.getClicks();data.totalCost += stats.getCost();data.totalConvertedClicks =+ stats.getConvertedClicks();
}}
this pulls in the total converted clicks into the column
@ChristiJOlson @SamuelDJames#PI_Scripts #AdWordsScripts
KEYWORD PERFORMANCE REPORT
YAY, it worked!Now I’ve got to figure out how to speed up our account audit
processes!
@ChristiJOlson @SamuelDJames#PI_Scripts #AdWordsScripts
EVENTUALLY I WANT TO AUTOMATE AUDITING
• Account set-up & settings
• SE Linked accounts audit My Business / Local Merchant Center Google Analytics Webmaster Tools
• Conversion tracking audit
• Goals & Events review
• Remarketing Audiences
• Shopping set-up
• Dynamic Search set-up
• Campaign settings & targeting
• Network settings & targeting
• Display settings & targeting
• Day Parting analysis
• Geo Targeting analysis
• Bid-modifier analysis
• Device Targeting analysis
• Ad delivery & rotation settings
• Ad extension audit
• Landing Page audit/analysis
• Campaign architecture
• Quality Score analysis
• Impression share analysis
• Keyword audit
• Negative keyword audit
• Match type audit
• Ad copy audit
• Display / Destination URL audit
• Missed Opportunity audit
• Performance audit
@ChristiJOlson @SamuelDJames#PI_Scripts #AdWordsScripts
I LIKE THE ACCOUNT AUDIT SCRIPT BUT
IT WASN’T THE FORMAT I WANTED
@ChristiJOlson @SamuelDJames#PI_Scripts #AdWordsScripts
I WANTED AN XLS SPREADSHEET
THAT COULD TRACK (AND MONITOR PROGRESS)
FOR ALL CLIENT ACCOUNTS
@ChristiJOlson @SamuelDJames#PI_Scripts #AdWordsScripts
BUT FOR NOW… USE THE ACCOUNT AUDIT SCRIPT
AS A FRAMEWORKTO BUILD OUT THE MORE IN-DEPTH
AUDIT
@ChristiJOlson @SamuelDJames#PI_Scripts #AdWordsScripts
STEP 1: MAPPING OUT WHAT THE SCRIPT DID
@ChristiJOlson @SamuelDJames#PI_Scripts #AdWordsScripts
STEP 2: ORGANIZE WHAT DATA WE NEED
@ChristiJOlson @SamuelDJames#PI_Scripts #AdWordsScripts
STEP 3: BREAK DOWN THE EXISTING SCRIPT INTO BITE SIZED PIECES
1. Campaign & Ad Group Names2. # of Keywords by Match Type & Negative3. Location Targeting Audit4. Extensions Audit5. Budget Audit
@ChristiJOlson @SamuelDJames#PI_Scripts #AdWordsScripts
STEP 4: CREATE REUSABLE PIECES OF CODE
NESTING FUNCTIONS
DECIDE ON THE ORDER OF THE FUNCTIONS AND PULLING DATA
@ChristiJOlson @SamuelDJames#PI_Scripts #AdWordsScripts
STEP 4: CREATE REUSABLE PIECES OF CODE
Create Header Rows within Spreadsheet
Start with Campaigns (because ad groups are within campaigns)
For Campaigns:Get Campaign NamesCalculate total KWDs & Negative KWDs
For Ad GroupsGet Ad Group NamesCalculate total KWDs & Negative KWDs
Push everything to the SpreadsheetLog 1 row per Campaign/Ad Group with Totals
@ChristiJOlson @SamuelDJames#PI_Scripts #AdWordsScripts
STEP 5: WRITE THE REUSABLE PIECES OF CODE
http://bit.ly/PI-GetCMP http://bit.ly/PI-GetAG
CAMPAIGN ITERATOR AD GROUP ITERATORS
@ChristiJOlson @SamuelDJames#PI_Scripts #AdWordsScripts
bit.ly/PI-SpreadsheetScript
STEP 5: WRITE THE REUSABLE PIECES OF CODE
PREP THE SPREADSHEET
@ChristiJOlson @SamuelDJames#PI_Scripts #AdWordsScripts
STEP 5: WRITE/EDIT CODE
GET CAMPAIGN & AD GROUP DATA
@ChristiJOlson @SamuelDJames#PI_Scripts #AdWordsScripts
STEP 5: WRITE/EDIT CODE
CREATE & WRITE TO GOOGLE DOC
@ChristiJOlson @SamuelDJames#PI_Scripts #AdWordsScripts
STEP 5: WRITE/EDIT CODE
COUNT KEYWORDS BY MATCH TYPE
This is the original code from the audit doc
@ChristiJOlson @SamuelDJames#PI_Scripts #AdWordsScripts
bit.ly/PI-KWDauditSCRIPT
STEP 6: PUT IT ALL TOGETHER
QA THE FINISHED PRODUCT
@ChristiJOlson @SamuelDJames#PI_Scripts #AdWordsScripts
Questions?
Get in the Game: Social Advertising Video
Platforms
June 24th @ 11:00am
Register atpointit.co/1HjrmrH
A link to view a recorded version of the webinar will be emailed within 48 hours!
NEXT WEBINAR:
G