ð íŒí¬ëšŒì€ ë§ìŒí /GA ì°ë ëì볎ë (W/Genspark)
ë구륌 ìí 묞ì? Genspark륌 ì²ì ì°ë êŽê³ í·ë§ìŒí°.
ìœë ë° ê±žëŠ¬ë ìê° â± ìœ 15ë¶ (ì€ìµ í¬íš 40~60ë¶)
결곌묌 ë§€ìŒ ì칚 êŽê³ ì±ê³Œ ìë ììœ ë©ìŒ + ìží°ëí°ëž ëì볎ë + íŽëŠ í ë²ìŒë¡ êŽê³ 죌 ì¬ëŒìŽë ë³Žê³ ì
ð ë°ìŽí° ëì볎ë, Gensparkë¡ ìŽë»ê² ë§ë€ìë (ìŽë³Žì©)
ð¡ ìŽ ì¹ì ì "ëë ì°ëЬ íì¬ ëì볎ë íë ë§ë€ê³ ì¶ë€" íë ë¶ë€ì ìí ìëŽì ëë€.
ìœë 몰ëŒë ë©ëë€. Genspark ì±í ì°œì ë°ìŽí°ìì€ì í롬íížë§ ë¶ì¬ë£ìŒë©Ž AIê° ììì ìí¬ì€íìŽì€ · í ìŽëž · ëì볎ë · ìë ëžëЬí ë©ìŒê¹ì§ ë§ë€ìŽì€ëë€.
ð¯ ìì±ë ëì볎ë 몚ìµ

죌ì êµ¬ì± ìì
- ð ìëš íí°ë° â êž°ê° í늬ì (ìµê·Œ 7ìŒ / 14ìŒ / ìŽë² ë¬ / ì ë² ë¬ / ì 첎) + 컀ì€í ë ì§ + ìŒ/죌/ì ì§ê³
- ð 6ê° KPI 칎ë â Spend · Revenue · ROAS · CTR · CPA · Purchases (ì êž° ëë¹ ìŠê° %)
- ð ížë ë ì°šíž â ìŒìë³ Spend + ROAS ìŽì€ ì¶
- ð¥§ ìº íìž ë¯¹ì€ â A vs B ì§ì¶ ëë
- ð ìº íìž ë¹êµí â ROAS ì ìì
- â ïž ì íšìš êŽê³ â ì§ì¶ $20â, 구맀 0걎 룰
- ð«§ ë²ëž ì°šíž â ìì¬ë³ Spend à ROAS à Purchases 3ì°šì
- ð¬ êŽê³ ìì¬ ììž â ìì¬ë³ ì±ê³Œ TOP 10
1. ìŽ ëì볎ëê° ë¬Žìì íŽì£Œëì?
ìž ê°ì§ê° ìëìŒë¡ ëìê°ëë€.
â ë§€ìŒ ì칚 Nì, ìŽì êŽê³ ì±ê³Œ ììœ ë©ìŒ
ì ë ì§ì¶Â·ë§€ì¶Â·ROAS·CPA·CTRì íëì 볌 ì ìë ëžëЬíìŽ ìŽë©ìŒë¡ ìµëë€. ì¬ëìŽ êŽê³ ë§€ëì 륌 ìŽìŽë³Žêž° ì ì ìŽì ì ížë¥Œ 뚌ì íì í ì ììŽì.
â ìžì ë ìŽìŽë³Žë ìží°ëí°ëž ëì볎ë
- êž°ê° íí° (ì€ë / ìŽì / ìµê·Œ 7ìŒ / 30ìŒ / ìŽë² ë¬ / 컀ì€í )
- ìŒë³Â·ì£Œë³Â·ìë³ ê·žë ìž ì í
- ìº íìžë³Â·ìì¬ë³ ì±ê³Œ 칎ë, ì íšìš ìì¬ ìë ê°ì§
- ìì¬ íšìš ë²ëž ì°šíž (X=ì§ì¶, Y=ROAS, ì í¬êž°=구맀ì)
â êŽê³ 죌 ë³Žê³ ì¬ëŒìŽë ìë ìì±
"ìŽë² 죌 늬í¬íž ë§ë€ìŽì€" íë§ëë¡ 8ì¥ì§ëЬ êŽê³ ì£Œì© ì¬ëŒìŽë ë°í¬ê° ë°ìŽí° êž°ë°ìŒë¡ ìì±ë©ëë€.
2. 묎ìì ì€ë¹íŽìŒ íëì?
| ë°ìŽí° ìì€ | ë°©ì | ìëí |
|---|---|---|
| Google Ads | Google Ads Scripts â ìíž | â ë§€ìŒ ì€ì Nì ìë |
| GA4 | Apps Script â ìíž | â ë§€ìŒ ì€ì Nì ìë |
| Meta Ads | Ads Managerìì CSV ë€ìŽë¡ë â ì±í ì°œ ì ë¡ë | ð ë§€ìŒ 3ë¶ ìë |
ð¡ Meta Adsë ìëííê³ ì¶ë€ë©Ž? íì¬ AI ë구(ì: GPTë íŽë¡ëìì Meta Ads 컀ë¥í°ë¥Œ ì°ê²°íŽì ì€íë ëìížì ë§€ìŒ ìëìŒë¡ ë¶ì í â ì ì€íí¬ ëì볎ëì ìëìŒë¡ ì°ê²°í ì ììµëë€. ìŽ íí 늬ìŒììë ì ê· ì ì ì ì§ì ì¥ë²œì ê³ ë €íŽ ìë ì ë¡ëë¡ ììíê³ , ìµìíŽì§ë©Ž ìëí ë구륌 ì¶ê°íë ê²ì ê¶ì¥í©ëë€.
3. STEP 1 · êµ¬êž ìíž ì€ë¹
ì ìíž íë ë§ë€ìŽì£Œìžì. ìŽëŠì ìì ë¡ê² (ì: "êŽê³ raw ë°ìŽí°").
ìŽ ìíž íëì ë€ì í 3ê°ê° ìëìŒë¡ ìì±ë©ëë€:
ads_daily_performance(Google Ads ì€í¬ëŠœížê° ìë ìì±)ga4_daily(GA4 ì€í¬ëŠœížê° ìë ìì±)- íì ì Meta CSV ë¶ì¬ë£êž°ì© í ìë ì¶ê°
ìíž URLì ë³µì¬íŽëìžì â ë ì€í¬ëŠœížì 몚ë íìí©ëë€.
4. STEP 2 · Google Ads ìë ì°ë ð¢
4-1. ì€í¬ëŠœíž ë±ë¡
- Google Ads ë¡ê·žìž
- ìëš ë©ëŽ ë구 â ìŒêŽ ìì â ì€í¬ëŠœíž
+ ì ì€í¬ëŠœížíŽëŠ- ì€í¬ëŠœíž ìŽëŠ:
ëì볎ë_ìíž_ëêž°í - ìë ìœë륌 ì ë¶ ë³µì¬íŽì ë¶ì¬ë£êž°
ð <b>google_ads_to_sheet.js</b> â íŽëŠíŽì ìœë íŒì¹êž°
/**
* Google Ads â Google Sheets ìë ìì§ ì€í¬ëŠœíž
* âââââââââââââââââââââââââââââââââââââââââââââ
* ìì¹: Google Ads â ë구 â ìŒêŽ ìì
â ì€í¬ëŠœíž â + ì ì€í¬ëŠœíž
* ì€í: ì¹ìž â 믞늬볎Ʞ(ì€ë¥ íìž) â ì€í â ë§€ìŒ ì€ì 6ì ì€ìŒì€
*
* ìíž êµ¬ì¡° (ìë ìì±):
* ads_daily_performance : ìŒìë³ êŽê³ ì±ê³Œ raw
* fx_rates : íìš ì°žì¡°ì© (USDâKRW)
*
* íì ì€ì : ìë SPREADSHEET_URL ë§ ë³žìž ìíž URLë¡ êµì²Ž
*/
// âââââââââââââââââââââââââââââââââââââââââââââââ
// ð ì¬êž°ë§ ìì íìžì
// âââââââââââââââââââââââââââââââââââââââââââââââ
const SPREADSHEET_URL = 'https://docs.google.com/spreadsheets/d/ì¬êž°ì_ìíž_URL_ì
ë ¥';
// ìì§ êž°ê°: LAST_7_DAYS / LAST_14_DAYS / LAST_30_DAYS / THIS_MONTH
const DATE_RANGE = 'LAST_7_DAYS';
// ìíž í ìŽëŠ (ìí멎 ë³ê²œ)
const SHEET_NAME = 'ads_daily_performance';
// âââââââââââââââââââââââââââââââââââââââââââââââ
// ë©ìž
// âââââââââââââââââââââââââââââââââââââââââââââââ
function main() {
const ss = SpreadsheetApp.openByUrl(SPREADSHEET_URL);
let sheet = ss.getSheetByName(SHEET_NAME);
if (!sheet) {
sheet = ss.insertSheet(SHEET_NAME);
sheet.appendRow([
'report_date', 'account_id', 'account_name',
'campaign_id', 'campaign_name', 'campaign_objective',
'adset_id', 'adset_name',
'ad_id', 'ad_name', 'creative_type', 'ad_status',
'spend', 'impressions', 'reach', 'frequency',
'clicks', 'link_clicks', 'ctr', 'cpc', 'cpm',
'purchases', 'purchase_value',
'add_to_cart', 'initiate_checkout',
'roas', 'cpa', 'currency', 'source'
]);
}
const account = AdsApp.currentAccount();
const accountId = account.getCustomerId();
const accountName = account.getName();
const currency = account.getCurrencyCode();
const report = AdsApp.report(
`SELECT
segments.date,
campaign.id, campaign.name, campaign.advertising_channel_type,
ad_group.id, ad_group.name,
ad_group_ad.ad.id, ad_group_ad.ad.name, ad_group_ad.ad.type, ad_group_ad.status,
metrics.cost_micros, metrics.impressions, metrics.clicks, metrics.ctr,
metrics.average_cpc, metrics.average_cpm,
metrics.conversions, metrics.conversions_value
FROM ad_group_ad
WHERE segments.date DURING ${DATE_RANGE}
AND ad_group_ad.status != 'REMOVED'`
);
const rows = report.rows();
const buffer = [];
while (rows.hasNext()) {
const r = rows.next();
const spend = Number(r['metrics.cost_micros']) / 1e6;
const conversions = Number(r['metrics.conversions']) || 0;
const revenue = Number(r['metrics.conversions_value']) || 0;
const clicks = Number(r['metrics.clicks']) || 0;
const impressions = Number(r['metrics.impressions']) || 0;
buffer.push([
r['segments.date'],
accountId, accountName,
r['campaign.id'], r['campaign.name'], r['campaign.advertising_channel_type'],
r['ad_group.id'], r['ad_group.name'],
r['ad_group_ad.ad.id'], r['ad_group_ad.ad.name'],
r['ad_group_ad.ad.type'], r['ad_group_ad.status'],
spend, impressions, 0, 0,
clicks, clicks, Number(r['metrics.ctr']) || 0,
Number(r['metrics.average_cpc']) / 1e6, Number(r['metrics.average_cpm']) / 1e6,
conversions, revenue,
0, 0,
spend > 0 ? revenue / spend : 0,
conversions > 0 ? spend / conversions : 0,
currency, 'google_ads_script'
]);
}
if (buffer.length === 0) {
Logger.log('ìì§ë ë°ìŽí°ê° ììµëë€.');
return;
}
// Ʞ졎 ë°ìŽí° ì€ ê°ì êž°ê°(report_date) ìì í append (upsert ë첎)
const existingDates = new Set(buffer.map(r => r[0]));
const lastRow = sheet.getLastRow();
if (lastRow > 1) {
const dateCol = sheet.getRange(2, 1, lastRow - 1, 1).getValues();
for (let i = dateCol.length - 1; i >= 0; i--) {
const d = dateCol[i][0];
const iso = d instanceof Date
? Utilities.formatDate(d, 'GMT+9', 'yyyy-MM-dd')
: String(d);
if (existingDates.has(iso)) sheet.deleteRow(i + 2);
}
}
sheet.getRange(sheet.getLastRow() + 1, 1, buffer.length, buffer[0].length).setValues(buffer);
Logger.log(`â
${buffer.length}í ì
ë¡ë ìë£ Â· ê³ì ${accountName}`);
}
4-2. ì€ì ìì
ìœë ë§š ì ìŽ ì€ì ë³žìž ìíž URLë¡ êµì²Ž:
const SPREADSHEET_URL = 'https://docs.google.com/spreadsheets/d/ì¬êž°ì_ìíž_URL_ì
ë ¥';4-3. ì¹ìž + í ì€íž
ì¹ìžíŽëŠ â êµ¬êž ê³ì ì¹ìž íì â ìížÂ·êŽê³ ë°ìŽí° ì ê·Œ íì©ë¯žëŠ¬ë³Žêž°íŽëŠ â ì€ë¥ ììŽ ë¡ê·žìâ Ní ì ë¡ë ìë£ëì€ë©Ž OKì€íí ë² ëë¬ì ìížì ë°ìŽí°ê° ë€ìŽìëì§ íìž
4-4. ë§€ìŒ ìë ì€í ì€ì
- ì€í¬ëŠœíž ëª©ë¡ í멎ìŒë¡ ëìê°êž°
- ë°©êž ë§ë ì€í¬ëŠœížì ë¹ë íŽëŠ
- ë¹ë: ë§€ìŒ, ìê°: ì€ì 6ì ì€ì â ì ì¥
â ìŽì ë§€ìŒ ì벜 6ìì ìŽì ê¹ì§ì Google Ads ì±ê³Œê° ìížì ìëìŒë¡ ìì ëë€.
5. STEP 3 · GA4 ìë ì°ë ð
5-1. Apps Script ìŽêž°
ê°ì ìížìì:
- íì¥ íë¡ê·žëš â Apps Script
- ì íë¡ì ížê° ìŽëŠœëë€. ìŽëŠ:
GA4_ëêž°í
5-2. â ïž ìë¹ì€ ì¶ê° (ì ìŒ ì€ì!)
ìŒìªœ ì¬ìŽëë° ìë¹ì€ ìì + íŽëŠ â 목ë¡ìì Google Analytics Data API ì í â ì¶ê°
â ìŽê±ž ì í멎 ì€í¬ëŠœížê° ì ë ì ëëë€. AnalyticsData is not defined ì€ë¥ê° ëšë©Ž ìŽ ëšê³ë¥Œ ë¹ ëšëа ê².5-3. ìœë ë¶ì¬ë£êž° + ìì± ID ì ë ¥
ìë ìœë륌 ì ë¶ ë³µì¬íŽì ë¶ì¬ë£êž°í ë€, GA4_PROPERTY_ID í ì€ë§ ë³žìž ê°ìŒë¡ ìì :
ð ga4_to_sheet.gsâ íŽëŠíŽì ìœë íŒì¹êž°
/**
* GA4 â Google Sheets ìë ìì§ ì€í¬ëŠœíž
* âââââââââââââââââââââââââââââââââââââââââ
* ìì¹: íŽë¹ ìížìì íì¥ íë¡ê·žëš â Apps Script
* â ïž íì: ìŒìªœ [ìë¹ì€] + ë²íŒ â "Google Analytics Data API" ì¶ê°
* ì€í ìì:
* 1) backfill90Days (곌거 90ìŒ ì±ì°êž°)
* 2) installDailyTrigger (ë§€ìŒ 07ì ìë ì€í ì€ì )
*
* ìíž í (ìë ìì±): ga4_daily
*/
// âââââââââââââââââââââââââââââââââââââââââââââââ
// ð ì¬êž°ë§ ìì íìžì
// âââââââââââââââââââââââââââââââââââââââââââââââ
const GA4_PROPERTY_ID = '000000000'; // ì: 366789012 (ì«ìë§)
const SHEET_TAB = 'ga4_daily';
// âââââââââââââââââââââââââââââââââââââââââââââââ
// ë§€ìŒ 07ì ížëŠ¬ê±° ì€ì¹ (ë± í ë²ë§ ì€í)
// âââââââââââââââââââââââââââââââââââââââââââââââ
function installDailyTrigger() {
// Ʞ졎 dailySync ížëŠ¬ê±° ììŒë©Ž ì ê±° (ì€ë³µ ë°©ì§)
ScriptApp.getProjectTriggers().forEach(t => {
if (t.getHandlerFunction() === 'dailySync') ScriptApp.deleteTrigger(t);
});
ScriptApp.newTrigger('dailySync')
.timeBased().atHour(7).everyDays(1)
.create();
Logger.log('â
ë§€ìŒ ì€ì 7ì dailySync ížëŠ¬ê±° ì€ì¹ ìë£');
}
// âââââââââââââââââââââââââââââââââââââââââââââââ
// ë§€ìŒ ì€í: ìŽì ë°ìŽí°ë§ upsert
// âââââââââââââââââââââââââââââââââââââââââââââââ
function dailySync() {
const y = new Date(); y.setDate(y.getDate() - 1);
const iso = Utilities.formatDate(y, 'GMT+9', 'yyyy-MM-dd');
fetchRange(iso, iso);
}
// âââââââââââââââââââââââââââââââââââââââââââââââ
// ìŽêž° ë°±í: ìµê·Œ 90ìŒ (ë± í ë²ë§ ì€í)
// âââââââââââââââââââââââââââââââââââââââââââââââ
function backfill90Days() {
const end = new Date(); end.setDate(end.getDate() - 1);
const start = new Date(); start.setDate(start.getDate() - 90);
fetchRange(
Utilities.formatDate(start, 'GMT+9', 'yyyy-MM-dd'),
Utilities.formatDate(end, 'GMT+9', 'yyyy-MM-dd')
);
}
// âââââââââââââââââââââââââââââââââââââââââââââââ
// ìœìŽ: GA4 Data API ížì¶ â ìíž upsert
// âââââââââââââââââââââââââââââââââââââââââââââââ
function fetchRange(startDate, endDate) {
const ss = SpreadsheetApp.getActiveSpreadsheet();
let sheet = ss.getSheetByName(SHEET_TAB);
if (!sheet) {
sheet = ss.insertSheet(SHEET_TAB);
sheet.appendRow([
'report_date', 'source_medium', 'campaign',
'sessions', 'active_users', 'new_users',
'engaged_sessions', 'avg_engagement_time',
'conversions', 'purchase_revenue', 'transactions',
'imported_at'
]);
}
const request = {
dateRanges: [{ startDate, endDate }],
dimensions: [
{ name: 'date' },
{ name: 'sessionSourceMedium' },
{ name: 'sessionCampaignName' }
],
metrics: [
{ name: 'sessions' }, { name: 'activeUsers' }, { name: 'newUsers' },
{ name: 'engagedSessions' }, { name: 'userEngagementDuration' },
{ name: 'conversions' }, { name: 'purchaseRevenue' }, { name: 'transactions' }
],
limit: 100000
};
const response = AnalyticsData.Properties.runReport(request, `properties/${GA4_PROPERTY_ID}`);
const rows = response.rows || [];
if (rows.length === 0) {
Logger.log(`â ïž ${startDate}~${endDate} ì¡°í 결곌 0걎`);
return;
}
const now = Utilities.formatDate(new Date(), 'GMT+9', 'yyyy-MM-dd HH:mm:ss');
const buffer = rows.map(r => {
const d = r.dimensionValues, m = r.metricValues;
const dateISO = `${d[0].value.slice(0,4)}-${d[0].value.slice(4,6)}-${d[0].value.slice(6,8)}`;
const sessions = Number(m[0].value) || 0;
const engTime = Number(m[4].value) || 0;
return [
dateISO, d[1].value, d[2].value,
sessions, Number(m[1].value) || 0, Number(m[2].value) || 0,
Number(m[3].value) || 0, sessions > 0 ? engTime / sessions : 0,
Number(m[5].value) || 0, Number(m[6].value) || 0, Number(m[7].value) || 0,
now
];
});
// upsert: ê°ì (date, source_medium, campaign) ì¡°í© ìì í append
const keys = new Set(buffer.map(r => `${r[0]}|${r[1]}|${r[2]}`));
const lastRow = sheet.getLastRow();
if (lastRow > 1) {
const existing = sheet.getRange(2, 1, lastRow - 1, 3).getValues();
for (let i = existing.length - 1; i >= 0; i--) {
const d = existing[i][0];
const iso = d instanceof Date
? Utilities.formatDate(d, 'GMT+9', 'yyyy-MM-dd')
: String(d);
const k = `${iso}|${existing[i][1]}|${existing[i][2]}`;
if (keys.has(k)) sheet.deleteRow(i + 2);
}
}
sheet.getRange(sheet.getLastRow() + 1, 1, buffer.length, buffer[0].length).setValues(buffer);
Logger.log(`â
${buffer.length}í · ${startDate}~${endDate}`);
}
GA4 ìì± ID ì°Ÿë ë²:
GA4 â êŽëЬ(âïž) â ìì± ì€ì â ìì± ìžë¶ ì 볎 â ìëš ìì± ID (9ì늬 ì«ì)
5-4. ë± í ë²ì© ì€í
ë€ì íšì륌 ììëë¡ í ë²ì©ë§ ì€í:
- ìëš íšì ëë¡ë€ìŽìì
backfill90Daysì í â â¶ ì€íâ 곌거 90ìŒì¹ ë°ìŽí°ê° ìížì ì±ìì§ëë€ (1~2ë¶ ìì)
- ë€ì ëë¡ë€ìŽìì
installDailyTriggerì í â â¶ ì€íâ ë§€ìŒ ì€ì 7ì ìë ì€í ížëŠ¬ê±° ì€ì¹
â ìŽì ë§€ìŒ ì€ì 7ìì GA4 ìŽì ë°ìŽí°ê° ìížì ìëìŒë¡ upsertë©ëë€.
6. STEP 4 · Meta Ads, ë€ìŽë² ë± CSV ìë ì ë¡ë ðµ
ìì§ê¹ì§ 몚ë AIê° ëªšë ë§€ì²Žì¬ ìŽë믌ì ìì ë¡ê² ì ìíì§ë 못íŽì. Meta Adsë í AIììë MCP ì°ëìŽ ê°ë¥íë í¬ëšžì¹ êž°ì ì ìŽëê¹
6-1. Ads Managerìì CSV ë€ìŽë¡ë
- Meta Ads Manager ë¡ê·žìž
- ìëš ì°ìž¡
ë³Žê³ ì â ì¬ì©ì ì§ì ë³Žê³ ì - 컬ëŒ: ìº íìžÂ·êŽê³ ìžížÂ·êŽê³ ·ì§ì¶Â·ë žì¶Â·ëë¬Â·íŽëŠÂ·CTR·CPC·CPM·구맀·구맀 ì í ê°Â·ì¥ë°êµ¬ë ì¶ê°Â·ê²°ì ìì
- ë¶ì êž°ê°: ìŽì (ëë ìíë êž°ê°)
- ì°ìž¡ ìëš ëŽë³ŽëŽêž° â CSV
6-2. ì±í ì°œì ì ë¡ë
Genspark ìí¬ì€íìŽì€ ì±í ì°œì ê·žëë¡ íìŒ ì²šë¶ í ìŽë ê² ë§í멎 ë©ëë€:
"ìŽì Meta êŽê³ raw ì
ë¡ëíìŽ. ads_daily_performance í
ìŽëžì upsertíŽì€"7. STEP 5 · Genspark ìí¬ì€íìŽì€ì ìíž ì°ê²°
- Genspark ìí¬ì€íìŽì€ í멎 ì°ìž¡ ìëš
ë°ìŽí° ìì€ ì¶ê° - Google Sheets ì í â ììì ë§ë ìíž URL ë¶ì¬ë£êž°
