← back to Rentv Adintel
scripts/import-google.js
174 lines
#!/usr/bin/env node
'use strict';
/**
* CLI: node scripts/import-google.js <ga4|gsc|google-ads>
*
* Calls src/connectors/* if present (guarded with try/require).
* Prints import summary. When connectors are unavailable, prints
* guidance on how to use the CSV upload fallback instead.
*
* Spec §6.20: Use only official APIs for GA4, GSC, Google Ads.
* No unofficial scraping, no cookie injection.
*
* @module scripts/import-google
*/
require('../lib/env');
const { pool } = require('../db');
const KIND = (process.argv[2] || '').toLowerCase();
const VALID = ['ga4', 'gsc', 'google-ads'];
if (!VALID.includes(KIND)) {
console.error('Usage: node scripts/import-google.js <ga4|gsc|google-ads>');
console.error('Valid kinds:', VALID.join(', '));
process.exit(1);
}
// ---------------------------------------------------------------------------
// Try to load the real connector
// ---------------------------------------------------------------------------
let connector = null;
const connectorKey = KIND === 'google-ads' ? 'google-ads' : KIND;
const connectorPaths = [
`../src/connectors/${connectorKey}`,
`../src/connectors/${connectorKey}/index`,
];
for (const cp of connectorPaths) {
try {
connector = require(cp);
break;
} catch (_) {
// not yet built
}
}
// ---------------------------------------------------------------------------
// CSV fallback guidance
// ---------------------------------------------------------------------------
const CSV_GUIDANCE = {
ga4: {
title: 'Google Analytics 4',
envVars: ['GOOGLE_SERVICE_ACCOUNT_JSON_BASE64', 'GA4_PROPERTY_ID'],
csvFallback: [
'1. In GA4, go to Reports > Export > CSV',
'2. Save the file locally',
'3. POST it to /api/v1/imports with source=ga4 as multipart/form-data',
' curl -F "file=@ga4-export.csv" -F "source=ga4" http://localhost:3001/api/v1/imports',
],
docsUrl: 'https://developers.google.com/analytics/devguides/reporting/data/v1',
setupSteps: [
'1. Create a Google Cloud service account with GA4 Viewer role.',
'2. Download the JSON key file.',
'3. Base64-encode it: base64 -i key.json',
'4. Set GOOGLE_SERVICE_ACCOUNT_JSON_BASE64 in .env',
'5. Set GA4_PROPERTY_ID to your numeric property ID (e.g. 123456789)',
'6. Re-run: node scripts/import-google.js ga4',
],
},
gsc: {
title: 'Google Search Console',
envVars: ['GOOGLE_SERVICE_ACCOUNT_JSON_BASE64', 'GSC_SITE_URL'],
csvFallback: [
'1. In GSC, go to Performance > Export > Download CSV',
'2. Save the file locally',
'3. POST it to /api/v1/imports with source=gsc',
' curl -F "file=@gsc-export.csv" -F "source=gsc" http://localhost:3001/api/v1/imports',
],
docsUrl: 'https://developers.google.com/webmaster-tools/v1/api_reference_index',
setupSteps: [
'1. Same service account as GA4 — add it as a full user in GSC settings.',
'2. Set GSC_SITE_URL to the exact property URL (e.g. https://rentv.com/)',
'3. Re-run: node scripts/import-google.js gsc',
],
},
'google-ads': {
title: 'Google Ads',
envVars: [
'GOOGLE_ADS_ENABLED', 'GOOGLE_ADS_DEVELOPER_TOKEN', 'GOOGLE_ADS_CUSTOMER_ID',
'GOOGLE_ADS_CLIENT_ID', 'GOOGLE_ADS_CLIENT_SECRET', 'GOOGLE_ADS_REFRESH_TOKEN',
],
csvFallback: [
'1. In Google Ads, go to Reports > Predefined reports > Campaign',
'2. Download as CSV',
'3. POST to /api/v1/imports with source=google-ads',
],
docsUrl: 'https://developers.google.com/google-ads/api/docs/start',
setupSteps: [
'1. Apply for a Google Ads developer token (can take 1-3 business days).',
'2. Create an OAuth2 client ID with Google Ads scope.',
'3. Generate a refresh token using OAuth2 playground.',
'4. Set all GOOGLE_ADS_* vars in .env',
'5. Set GOOGLE_ADS_ENABLED=true',
'6. Re-run: node scripts/import-google.js google-ads',
],
},
};
// ---------------------------------------------------------------------------
// Check env vars
// ---------------------------------------------------------------------------
function checkEnvVars(vars) {
const missing = vars.filter((v) => !process.env[v]);
return missing;
}
// ---------------------------------------------------------------------------
// Run import
// ---------------------------------------------------------------------------
(async () => {
console.log(`\n[import-google] Importing: ${KIND}`);
const guide = CSV_GUIDANCE[KIND];
if (connector && typeof connector.runImport === 'function') {
// Real connector present
const missing = checkEnvVars(guide.envVars);
if (missing.length > 0) {
console.error(`[import-google] Missing required env vars for ${KIND}:`);
missing.forEach((v) => console.error(` - ${v}`));
console.error('\nSetup steps:');
guide.setupSteps.forEach((s) => console.error(' ', s));
await pool.end();
process.exit(1);
}
console.log('[import-google] Connector found. Running import...');
try {
const result = await connector.runImport();
console.log('[import-google] Import complete:');
console.log(JSON.stringify(result, null, 2));
} catch (err) {
console.error('[import-google] Import failed:', err.message);
console.error(err.stack);
await pool.end();
process.exit(1);
}
await pool.end();
return;
}
// Connector not yet built — print guidance
console.log(`[import-google] ${guide.title} connector not yet installed.`);
console.log('\nRequired environment variables:');
guide.envVars.forEach((v) => {
const set = !!process.env[v];
console.log(` ${set ? '[SET]' : '[MISSING]'} ${v}`);
});
if (KIND === 'google-ads' && process.env.GOOGLE_ADS_ENABLED !== 'true') {
console.log('\n Note: GOOGLE_ADS_ENABLED must be "true" to activate this connector.');
}
console.log('\nSetup steps:');
guide.setupSteps.forEach((s) => console.log(' ', s));
console.log(`\nAPI documentation: ${guide.docsUrl}`);
console.log('\nCSV upload fallback (works now without connector):');
guide.csvFallback.forEach((s) => console.log(' ', s));
await pool.end();
process.exit(0);
})();