Bulks Similar helps you discover companies and domains similar to your target prospects. This feature is invaluable for competitive analysis, market research, and expanding your total addressable market by finding lookalike companies.
Key Features
Competitor Discovery: Find domains similar to your target companies
Market Expansion: Identify new prospects in similar industries or niches
Batch Processing: Process up to 500 domains simultaneously
Industry Insights: Discover companies in the same vertical or market segment
Email Discovery: Find contact information for similar companies
Export Capabilities: Download comprehensive results for further analysis
How Similar Domain Bulk Works
Input Reference Domains: Provide domains of companies you want to find similar matches for
Configure Search Parameters: Set email type preferences and result limits
Launch Analysis: Start the similarity search algorithm
Review Results: Examine discovered similar domains and their contact information
Export Data: Download results for integration with your CRM or outreach tools
Limitations
Each Bulk is limited to 500 domains
Additional rows will be skipped
Some special or unexpected characters may be deleted in the file
Invalid websites won't be imported
Duplicate URLs won't be imported
For better results, we use the domain name instead of the company name
// Reference domains for finding similar companiesreferenceDomains := []string{ "stripe.com", "square.com", "paypal.com", "adyen.com", "checkout.com",}params := &models.BulkCreateParams{ Name: "Similar Companies - Fintech Payment Processors", List: strings.Join(referenceDomains, "\n"), Sources: true, // Include sources for context Notifie: true, // Notify when complete}// Create similar domain bulk operationresponse, err := client.CreateBulk(models.BulkTypeSimilar, params)if err != nil { log.Fatal("Failed to create similar domain bulk:", err)}bulkID := *response.Data.IDfmt.Printf("Created similar domain bulk with ID: %d\n", bulkID)
Creating Similar Domain Bulk from CSV File
Code
// Create similar domain bulk from CSV fileparams := &models.BulkCreateParams{ Name: "Market Analysis - SaaS Competitors", Delimiter: ",", Column: 1, // Domain column (1-based index) Sources: true, Notifie: true,}// Upload CSV with reference domainsresponse, err := client.CreateBulkWithFile( models.BulkTypeSimilar, params, "/path/to/reference-domains.csv",)if err != nil { log.Fatal("Failed to create bulk with file:", err)}bulkID := *response.Data.IDfmt.Printf("Created similar domain bulk: %d\n", bulkID)
Single Similar Domain Query (for comparison)
Code
// Find similar domains for a single companytargetDomain := "shopify.com"similarDomains, err := client.SimilarDomains(targetDomain)if err != nil { log.Printf("Failed to find similar domains for %s: %v", targetDomain, err)} else { fmt.Printf("Similar domains to %s:\n", targetDomain) for _, domain := range similarDomains.Data.Similar { fmt.Printf("- %s (Score: %d)\n", domain.Domain, domain.Score) }}
Launching and Monitoring Similar Domain Discovery
Code
// Launch the similar domain discoverylaunchResponse, err := client.LaunchBulk(models.BulkTypeSimilar, bulkID)if err != nil { log.Fatal("Failed to launch similar domain bulk:", err)}fmt.Println("Similar domain discovery started!")// Monitor progressstartTime := time.Now()for { progress, err := client.GetBulkProgress(models.BulkTypeSimilar, bulkID) if err != nil { log.Printf("Error checking progress: %v", err) time.Sleep(30 * time.Second) continue } elapsed := time.Since(startTime).Round(time.Second) fmt.Printf("Discovery progress: %d%% (%d domains processed) - %v elapsed\n", progress.Progress, progress.Processed, elapsed, ) if progress.Status { fmt.Println("Similar domain discovery completed!") break } // Check every 45 seconds (similar domain discovery can take time) time.Sleep(45 * time.Second)}
Retrieving Similar Domain Results
Code
// Get detailed resultsbulk, err := client.GetBulk(models.BulkTypeSimilar, bulkID)if err != nil { log.Fatal("Failed to get bulk details:", err)}bulkInfo := bulk.Data[0]fmt.Printf("Similar Domain Discovery Results:\n")fmt.Printf("- Campaign: %s\n", bulkInfo.Name)fmt.Printf("- Status: %v\n", bulkInfo.Status)fmt.Printf("- Reference Domains Processed: %d\n", bulkInfo.Processed)if bulkInfo.TotalEmails != nil { fmt.Printf("- Contact Emails Found: %d\n", *bulkInfo.TotalEmails)}// Download all results with similar domains and contactserr = client.SaveBulkResults( models.BulkTypeSimilar, bulkID, "similar-domains.csv", "full",)if err != nil { log.Fatal("Failed to download results:", err)}fmt.Println("Similar domain results saved to similar-domains.csv")
Managing Similar Domain Operations
Code
// List all similar domain bulksparams := &models.BulkGetParams{ Page: 1, Limit: 10, Direction: "desc", Filter: "all",}bulks, err := client.GetAllSimilarBulks(params)if err != nil { log.Fatal("Failed to get similar domain bulks:", err)}fmt.Printf("Similar Domain Operations:\n")for _, bulk := range bulks.Data { status := "In Progress" if bulk.Status { status = "Completed" } fmt.Printf("- %s (ID: %d)\n", bulk.Name, bulk.BulkID) fmt.Printf(" Status: %s | Progress: %d%% | Processed: %d\n", status, bulk.Progress, bulk.Processed) if bulk.TotalEmails != nil && *bulk.TotalEmails > 0 { fmt.Printf(" Emails Found: %d\n", *bulk.TotalEmails) } created := bulk.CreatedAt.Format("2006-01-02 15:04") fmt.Printf(" Created: %s\n", created) fmt.Println()}// Archive old analysesfor _, bulk := range bulks.Data { if bulk.Status && time.Since(bulk.CreatedAt) > 14*24*time.Hour { // 14 days old _, err := client.ArchiveBulk(models.BulkTypeSimilar, bulk.BulkID) if err != nil { log.Printf("Failed to archive bulk %d: %v", bulk.BulkID, err) } else { fmt.Printf("Archived old analysis: %s\n", bulk.Name) } }}
Advanced Market Analysis Workflow
Code
type SimilarDomainResult struct { ReferenceDomain string SimilarDomain string SimilarityScore int Industry string CompanySize string ContactEmails []string Technologies []string}type MarketAnalysis struct { ReferenceDomains []string SimilarDomainsFound int ContactsDiscovered int TopIndustries map[string]int CompetitorDomains []string}func performMarketAnalysis(client *tomba.Tomba, referenceDomains []string, industry string) (*MarketAnalysis, error) { // Validate domain count if len(referenceDomains) > 500 { log.Printf("Warning: Limiting reference domains from %d to 500", len(referenceDomains)) referenceDomains = referenceDomains[:500] } log.Printf("Starting market analysis for %d reference domains in %s industry", len(referenceDomains), industry) // Step 1: Create similar domain bulk params := &models.BulkCreateParams{ Name: fmt.Sprintf("Market Analysis - %s - %s", strings.Title(industry), time.Now().Format("2006-01-02")), List: strings.Join(referenceDomains, "\n"), Sources: true, Notifie: false, // Don't notify for analysis } response, err := client.CreateBulk(models.BulkTypeSimilar, params) if err != nil { return nil, fmt.Errorf("failed to create similar domain bulk: %w", err) } bulkID := *response.Data.ID log.Printf("Created market analysis bulk: %d", bulkID) // Step 2: Launch and monitor _, err = client.LaunchBulk(models.BulkTypeSimilar, bulkID) if err != nil { return nil, fmt.Errorf("failed to launch bulk: %w", err) } // Monitor with extended timeout for similar domain discovery timeout := time.After(90 * time.Minute) ticker := time.NewTicker(60 * time.Second) defer ticker.Stop() startTime := time.Now() for { select { case <-timeout: return nil, fmt.Errorf("market analysis timed out after 90 minutes") case <-ticker.C: progress, err := client.GetBulkProgress(models.BulkTypeSimilar, bulkID) if err != nil { log.Printf("Error checking progress: %v", err) continue } if progress.Progress%20 == 0 || progress.Status { elapsed := time.Since(startTime).Round(time.Second) log.Printf("Market analysis: %d%% (%d domains processed) - %v", progress.Progress, progress.Processed, elapsed) } if progress.Status { // Step 3: Analyze results return analyzeMarketResults(client, bulkID, referenceDomains, startTime) } } }}func analyzeMarketResults(client *tomba.Tomba, bulkID int64, referenceDomains []string, startTime time.Time) (*MarketAnalysis, error) { // Download results timestamp := time.Now().Format("20060102-150405") resultsFile := fmt.Sprintf("market-analysis-%s.csv", timestamp) err := client.SaveBulkResults(models.BulkTypeSimilar, bulkID, resultsFile, "full") if err != nil { return nil, fmt.Errorf("failed to download results: %w", err) } log.Printf("Downloaded market analysis results to: %s", resultsFile) // Parse and analyze results results, err := parseSimilarDomainResults(resultsFile) if err != nil { log.Printf("Warning: Could not parse results for detailed analysis: %v", err) // Continue with basic analysis from bulk info bulk, err := client.GetBulk(models.BulkTypeSimilar, bulkID) if err != nil { return nil, err } info := bulk.Data[0] analysis := &MarketAnalysis{ ReferenceDomains: referenceDomains, } if info.TotalEmails != nil { analysis.ContactsDiscovered = *info.TotalEmails } return analysis, nil } // Detailed analysis analysis := &MarketAnalysis{ ReferenceDomains: referenceDomains, SimilarDomainsFound: len(results), TopIndustries: make(map[string]int), } // Extract unique similar domains and analyze domainSet := make(map[string]bool) totalContacts := 0 for _, result := range results { if result.SimilarDomain != "" { domainSet[result.SimilarDomain] = true totalContacts += len(result.ContactEmails) if result.Industry != "" { analysis.TopIndustries[result.Industry]++ } } } // Convert domain set to slice for domain := range domainSet { analysis.CompetitorDomains = append(analysis.CompetitorDomains, domain) } analysis.SimilarDomainsFound = len(analysis.CompetitorDomains) analysis.ContactsDiscovered = totalContacts duration := time.Since(startTime) log.Printf("Market analysis completed in %v:", duration.Round(time.Second)) log.Printf("- Reference domains: %d", len(analysis.ReferenceDomains)) log.Printf("- Similar domains found: %d", analysis.SimilarDomainsFound) log.Printf("- Contact emails discovered: %d", analysis.ContactsDiscovered) if len(analysis.TopIndustries) > 0 { log.Printf("- Industries identified: %d", len(analysis.TopIndustries)) } return analysis, nil}func parseSimilarDomainResults(filename string) ([]SimilarDomainResult, error) { file, err := os.Open(filename) if err != nil { return nil, err } defer file.Close() reader := csv.NewReader(file) records, err := reader.ReadAll() if err != nil { return nil, err } var results []SimilarDomainResult // Parse CSV results (simplified - actual format may vary) for i := 1; i < len(records); i++ { // Skip header record := records[i] if len(record) < 2 { continue } result := SimilarDomainResult{ ReferenceDomain: getCSVField(record, 0), SimilarDomain: getCSVField(record, 1), } // Parse additional fields if available if len(record) > 2 { fmt.Sscanf(getCSVField(record, 2), "%d", &result.SimilarityScore) } if len(record) > 3 { result.Industry = getCSVField(record, 3) } if len(record) > 4 { result.CompanySize = getCSVField(record, 4) } if len(record) > 5 { emails := getCSVField(record, 5) if emails != "" { result.ContactEmails = strings.Split(emails, ";") } } results = append(results, result) } return results, nil}func getCSVField(record []string, index int) string { if index < len(record) { return strings.Trim(record[index], `"`) } return ""}// Generate market reportfunc generateMarketReport(analysis *MarketAnalysis, outputFile string) error { file, err := os.Create(outputFile) if err != nil { return err } defer file.Close() fmt.Fprintf(file, "Market Analysis Report\n") fmt.Fprintf(file, "Generated: %s\n\n", time.Now().Format("2006-01-02 15:04:05")) fmt.Fprintf(file, "Reference Domains Analyzed: %d\n", len(analysis.ReferenceDomains)) fmt.Fprintf(file, "Similar Domains Discovered: %d\n", analysis.SimilarDomainsFound) fmt.Fprintf(file, "Contact Emails Found: %d\n", analysis.ContactsDiscovered) if len(analysis.TopIndustries) > 0 { fmt.Fprintf(file, "\nIndustry Distribution:\n") for industry, count := range analysis.TopIndustries { fmt.Fprintf(file, "- %s: %d companies\n", industry, count) } } if len(analysis.CompetitorDomains) > 0 { fmt.Fprintf(file, "\nDiscovered Competitor Domains:\n") for i, domain := range analysis.CompetitorDomains { fmt.Fprintf(file, "%d. %s\n", i+1, domain) if i >= 49 { // Limit to top 50 fmt.Fprintf(file, "... and %d more\n", len(analysis.CompetitorDomains)-50) break } } } return nil}// Complete market analysis workflowfunc runCompetitorAnalysis(client *tomba.Tomba, csvPath, industry string) error { // Read reference domains from CSV file, err := os.Open(csvPath) if err != nil { return fmt.Errorf("failed to open CSV: %w", err) } defer file.Close() reader := csv.NewReader(file) records, err := reader.ReadAll() if err != nil { return fmt.Errorf("failed to read CSV: %w", err) } var referenceDomains []string for i, record := range records { if i == 0 || len(record) == 0 { // Skip header and empty rows continue } domain := strings.TrimSpace(record[0]) if domain != "" { referenceDomains = append(referenceDomains, domain) } } if len(referenceDomains) == 0 { return fmt.Errorf("no valid reference domains found in CSV") } log.Printf("Starting competitor analysis with %d reference domains", len(referenceDomains)) // Perform market analysis analysis, err := performMarketAnalysis(client, referenceDomains, industry) if err != nil { return fmt.Errorf("market analysis failed: %w", err) } // Generate report timestamp := time.Now().Format("20060102-150405") reportFile := fmt.Sprintf("market-report-%s.txt", timestamp) err = generateMarketReport(analysis, reportFile) if err != nil { log.Printf("Warning: Could not generate report file: %v", err) } else { log.Printf("Market analysis report saved to: %s", reportFile) } // Print summary expansionRate := float64(analysis.SimilarDomainsFound) / float64(len(analysis.ReferenceDomains)) * 100 fmt.Printf("\nCompetitor Analysis Summary:\n") fmt.Printf("Reference Companies: %d\n", len(analysis.ReferenceDomains)) fmt.Printf("Similar Companies Found: %d\n", analysis.SimilarDomainsFound) fmt.Printf("Market Expansion Rate: %.1fx\n", expansionRate/100) fmt.Printf("Contact Emails Discovered: %d\n", analysis.ContactsDiscovered) return nil}// Usage examplefunc main() { client := tomba.NewTomba("your-api-key", "your-secret-key") err := runCompetitorAnalysis(client, "reference-companies.csv", "fintech") if err != nil { log.Fatal("Competitor analysis failed:", err) }}