UNPKG

meta-ads-scraper

Version:

Meta Ad Library scraper with AI-powered competitive analysis using Apify and Gemini 2.0 Flash

425 lines (341 loc) 12.3 kB
# Meta Ads Scraper A powerful TypeScript library for scraping Meta (Facebook) Ad Library data and performing AI-powered competitive analysis using Google's Gemini 2.0 Flash model. ## Features - 🚀 **Meta Ad Library Scraping**: Extract ad data from Facebook's Ad Library using Apify - 🤖 **AI-Powered Analysis**: Analyze competitor ads with Google Gemini 2.0 Flash - 📊 **Competitive Intelligence**: Generate strategic insights and ad concepts - 🔄 **Smart Caching**: Reuse existing scraped data to save time and costs - 📝 **TypeScript Support**: Full type safety and IntelliSense support ## Installation ```bash npm install meta-ads-scraper ``` ## Prerequisites You'll need API keys for: - **Apify**: For scraping Meta Ad Library data - **Google Gemini**: For AI analysis Get your keys: - [Apify API Token](https://console.apify.com/account/integrations) - [Google AI Studio API Key](https://makersuite.google.com/app/apikey) ## Quick Start ### Basic Usage ```typescript import { MetaAdsScraper, GeminiAnalyzer, performCompetitiveAnalysis } from 'meta-ads-scraper'; // Set up your API keys process.env.APIFY_TOKEN = 'your-apify-token'; process.env.GEMINI_API_KEY = 'your-gemini-api-key'; // Perform complete competitive analysis const result = await performCompetitiveAnalysis({ clientDetails: ` Your company is a leading e-commerce platform specializing in fast delivery and competitive pricing... `, competitors: [ { name: 'Competitor 1', url: 'https://www.facebook.com/ads/library/?active_status=active&ad_type=all&country=ALL&is_targeted_country=false&media_type=all&search_type=page&view_all_page_id=123456789' }, { name: 'Competitor 2', url: 'https://www.facebook.com/ads/library/?active_status=active&ad_type=all&country=ALL&is_targeted_country=false&media_type=all&search_type=page&view_all_page_id=987654321' } ], scrapingOptions: { maxResults: 20, useExistingRun: true }, apiKeys: { apifyToken: 'your-apify-token', // Optional: falls back to APIFY_TOKEN env var geminiApiKey: 'your-gemini-api-key' // Optional: falls back to GEMINI_API_KEY env var } }); console.log('Analysis Results:', result); // Parse the results into structured JSON format import { parseCompetitiveAnalysisResult } from 'meta-ads-scraper'; const parsedResult = parseCompetitiveAnalysisResult(result); console.log('Parsed Restructured Ads:', parsedResult.restructuredAds); console.log('Parsed Industry Analysis:', parsedResult.industryAnalysis); ``` ### Step-by-Step Usage ```typescript import { MetaAdsScraper, GeminiAnalyzer } from 'meta-ads-scraper'; // 1. Scrape ads const scraper = new MetaAdsScraper(process.env.APIFY_TOKEN); const ads = await scraper.getAds(competitorUrl, { maxResults: 10, useExistingRun: true }); // 2. Analyze with AI const analyzer = new GeminiAnalyzer(process.env.GEMINI_API_KEY); // Restructure ads by company const restructuredAds = await analyzer.restructureAds(ads); // Analyze each company const companyAnalysis = await analyzer.getTopIdeasPerCompany( 'Company Name', restructuredAds.text ); // Generate industry insights const industryAnalysis = await analyzer.industryWriteup([companyAnalysis]); // Create ad concepts const adConcepts = await analyzer.generateAdIdeas( [companyAnalysis], industryAnalysis, 'Your company details...' ); ``` ## API Reference ### Core Classes #### `MetaAdsScraper` Scrapes Meta Ad Library data using Apify. ```typescript const scraper = new MetaAdsScraper(apiToken?: string); // Get ads from a Meta Ad Library URL const ads = await scraper.getAds(url: string, options?: { maxResults?: number; useExistingRun?: boolean; }); ``` #### `GeminiAnalyzer` Performs AI-powered analysis of scraped ad data. ```typescript const analyzer = new GeminiAnalyzer(apiKey?: string); // Restructure raw ad data into organized format const restructured = await analyzer.restructureAds(ads: MetaAdData[]); // Extract company-specific data const companyText = analyzer.extractCompanyText(text: string, companyName: string); // Analyze a specific company const analysis = await analyzer.getTopIdeasPerCompany(companyName: string, text: string); // Generate industry insights const industry = await analyzer.industryWriteup(analyses: CompanyAnalysisResult[]); // Create ad concepts const concepts = await analyzer.generateAdIdeas( companyAnalyses: CompanyAnalysisResult[], industryAnalysis: IndustryAnalysisResult, clientDetails: string ); ``` ### Main Function #### `performCompetitiveAnalysis(config: CompetitiveAnalysisConfig)` Performs a complete competitive analysis pipeline. ```typescript interface CompetitiveAnalysisConfig { clientDetails: string; competitors: Competitor[]; scrapingOptions?: ScrapingOptions; apiKeys?: { apifyToken?: string; geminiApiKey?: string; }; } interface Competitor { name: string; url: string; } interface ScrapingOptions { maxResults?: number; useExistingRun?: boolean; } ``` ### Parsing Functions Convert the text-based results into structured JSON format: ```typescript import { parseCompetitiveAnalysisResult, parseRestructuredAds, parseIndustryAnalysis, parseCompanyAnalysis } from 'meta-ads-scraper'; // Parse the complete result const parsedResult = parseCompetitiveAnalysisResult(result); // Or parse individual components const parsedAds = parseRestructuredAds(result.restructuredAds); const parsedIndustry = parseIndustryAnalysis(result.industryAnalysis.text); const parsedCompany = parseCompanyAnalysis(result.companyAnalyses[0].text); // Example parsed structure: console.log(parsedResult.restructuredAds.companies[0].ads[0]); // { // adId: "768050109455085", // assetType: "Unknown (likely motion based on the presence of \"cards\")", // format: "Carousel (2 cards)", // visualHooks: ["💧 water droplet emoji, implying skincare or hydration."], // audiencesAddressed: ["Shoppers interested in Early Bird Deals and the Big Billion Days sale."], // ageGroup: "18-45 (typical online shoppers).", // graphicIdentity: ["Flipkart branding (colors not specified in data). The focus is on promoting the sale event."], // copywritingHooks: ["Early Bird Deals Starts 8th September", "💧 Glow season starts now!"], // copywritingAngles: ["Limited-time offer, emphasis on deals, pre-sale hype for Big Billion Days. Focus on skincare/beauty category."], // usps: ["Early access to deals before the main Big Billion Days sale."], // cta: "Learn more", // adSummary: "A carousel ad promoting Flipkart's Early Bird Deals...", // engagementMetrics: "Not available", // duration: "Null (likely short video or multiple static images)", // targetingAssumptions: ["Existing Flipkart users, individuals interested in online shopping..."], // publisherPlatform: ["FACEBOOK", "INSTAGRAM"] // } // Example parsed company analysis structure: console.log(parsedResult.companyAnalyses[0]); // { // companyName: "Flipkart", // creativeSummary: "The Flipkart ads analyzed consistently promote their Big Billion Days sale...", // topCreatives: { // description: "All the ads follow a similar structure...", // primaryHook: "Early Bird Deals Starts 8th September, combined with Big Billion Days branding...", // cta: "Learn More", // ctaFraming: "framed as a way to access early deals and wide product selection", // visualComposition: "The visuals likely utilize a vibrant and festive color scheme...", // copywritingTone: "The tone is promotional and benefit-oriented..." // }, // whatWorks: [ // { // title: "Consistent Branding", // description: "Strong, consistent use of Big Billion Days branding..." // } // ], // missedOpportunities: [ // { // title: "Generic Learn More CTA", // description: "The consistent use of Learn More is a missed opportunity..." // } // ], // actionableTakeaways: [ // { // title: "Test Category-Specific CTAs", // insight: "Generic CTAs limit conversion potential.", // suggestedFormat: "Carousel ads with category-specific CTAs on each card...", // hypothesis: "Category-specific CTAs will increase click-through rates..." // } // ] // } ``` ### Types ```typescript interface MetaAdData { metadata: { page_name: string; ad_archive_id: string; scraped_at: string; }; ad_content: { title: string; body: string; cta_text: string; cta_type: string; link_url: string; cards: Array<{ title: string; body: string; }>; }; distribution: { publisher_platform: string[]; }; status: { is_active: boolean; }; performance: { impressions?: number; spend?: number; currency: string; }; } interface CompetitiveAnalysisResult { clientDetails: string; competitors: Competitor[]; totalAdsScraped: number; restructuredAds: string; companyAnalyses: CompanyAnalysisResult[]; industryAnalysis: IndustryAnalysisResult; adConcepts: AdConceptResult; analysisMetadata: { timestamp: string; scrapingOptions?: ScrapingOptions; totalCompanies: number; }; } ``` ## Configuration ### API Keys You can provide API keys in two ways: #### Option 1: Environment Variables (Recommended for production) ```bash # Required APIFY_TOKEN=your-apify-token GEMINI_API_KEY=your-gemini-api-key # Optional NODE_ENV=production ``` #### Option 2: Pass directly in config (Useful for testing or multiple accounts) ```typescript const result = await performCompetitiveAnalysis({ clientDetails: 'Your company description...', competitors: [...], apiKeys: { apifyToken: 'your-apify-token', geminiApiKey: 'your-gemini-api-key' } }); ``` **Note**: If you provide API keys in the config, they will take precedence over environment variables. If neither is provided, the function will throw an error. ### Meta Ad Library URLs The scraper works with Meta Ad Library URLs in this format: ``` https://www.facebook.com/ads/library/?active_status=active&ad_type=all&country=ALL&is_targeted_country=false&media_type=all&search_type=page&view_all_page_id=PAGE_ID ``` ## Advanced Usage ### Custom Analysis Pipeline ```typescript import { MetaAdsScraper, GeminiAnalyzer } from 'meta-ads-scraper'; async function customAnalysis() { const scraper = new MetaAdsScraper(); const analyzer = new GeminiAnalyzer(); // Scrape multiple competitors const allAds = []; for (const competitor of competitors) { const ads = await scraper.getAds(competitor.url); allAds.push(...ads); } // Custom analysis steps const restructured = await analyzer.restructureAds(allAds); // Process each company individually const analyses = []; for (const company of companies) { const companyText = analyzer.extractCompanyText(restructured.text, company); const analysis = await analyzer.getTopIdeasPerCompany(company, companyText); analyses.push(analysis); } return analyses; } ``` ### Error Handling ```typescript try { const result = await performCompetitiveAnalysis(config); console.log('Analysis completed successfully'); } catch (error) { if (error.message.includes('API key')) { console.error('Invalid API key provided'); } else if (error.message.includes('URL')) { console.error('Invalid Meta Ad Library URL'); } else { console.error('Analysis failed:', error.message); } } ``` ## Contributing 1. Fork the repository 2. Create your feature branch (`git checkout -b feature/amazing-feature`) 3. Commit your changes (`git commit -m 'Add some amazing feature'`) 4. Push to the branch (`git push origin feature/amazing-feature`) 5. Open a Pull Request ## License This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. ## Support - 📧 Email: support@example.com - 🐛 Issues: [GitHub Issues](https://github.com/yourusername/meta-ads-scraper/issues) - 📖 Documentation: [GitHub Wiki](https://github.com/yourusername/meta-ads-scraper/wiki) ## Changelog ### v1.0.0 - Initial release - Meta Ad Library scraping with Apify - AI-powered competitive analysis with Gemini 2.0 Flash - Complete TypeScript support - Smart caching and reuse of existing data