AP

apollo-performance-tuning

Speed up Apollo.io API integrations with caching and connection management.

Install

mkdir -p .claude/skills/apollo-performance-tuning && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/5995" && unzip -o skill.zip -d .claude/skills/apollo-performance-tuning && rm skill.zip

Installs to .claude/skills/apollo-performance-tuning

Activation

This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.

Optimize Apollo.io API performance.
35 charsno explicit “when” trigger
Intermediate

Key capabilities

  • Implement TCP connection pooling
  • Cache API responses with per-endpoint TTLs
  • Execute bulk enrichment operations
  • Perform parallel API searches with concurrency control
  • Slim response payloads to reduce memory usage
  • Benchmark API endpoint latency

How it works

The skill provides patterns for reusing TCP connections, caching responses via LRU, and batching requests to minimize latency and credit usage. It also includes utilities for parallelizing searches and slimming down large API response objects.

Inputs & outputs

You give it
API endpoint, request parameters, and concurrency settings
You get back
Optimized API client, cached data, or performance benchmark metrics

When to use apollo-performance-tuning

  • Implement connection pooling for TCP reuse
  • Cache API responses with TTL settings
  • Reduce API latency for enrichment tasks
  • Batch bulk operations to optimize performance

About this skill

Apollo Performance Tuning

Overview

Optimize Apollo.io API performance through response caching, connection pooling, bulk operations, parallel fetching, and result slimming. Key insight: search is free but slow (~500ms), enrichment costs credits — cache aggressively and batch enrichment calls.

Prerequisites

  • Valid Apollo API key
  • Node.js 18+

Instructions

Step 1: Connection Pooling

Reuse TCP connections to avoid TLS handshake overhead on every request.

// src/apollo/optimized-client.ts
import axios from 'axios';
import https from 'https';

const httpsAgent = new https.Agent({
  keepAlive: true,
  maxSockets: 10,
  maxFreeSockets: 5,
  timeout: 30_000,
});

export const optimizedClient = axios.create({
  baseURL: 'https://api.apollo.io/api/v1',
  headers: { 'Content-Type': 'application/json', 'x-api-key': process.env.APOLLO_API_KEY! },
  httpsAgent,
  timeout: 15_000,
});

Step 2: Response Caching with Per-Endpoint TTLs

// src/apollo/cache.ts
import { LRUCache } from 'lru-cache';

// Different TTLs based on data volatility
const CACHE_TTLS: Record<string, number> = {
  '/organizations/enrich': 24 * 60 * 60 * 1000,    // 24h — company data rarely changes
  '/people/match': 4 * 60 * 60 * 1000,              // 4h — contact data changes occasionally
  '/mixed_people/api_search': 15 * 60 * 1000,       // 15min — search results are dynamic
  '/mixed_companies/search': 30 * 60 * 1000,         // 30min — company search
  '/contact_stages': 60 * 60 * 1000,                 // 1h — stages rarely change
};

const cache = new LRUCache<string, { data: any; at: number }>({
  max: 5000,
  maxSize: 50 * 1024 * 1024,
  sizeCalculation: (v) => JSON.stringify(v).length,
});

function cacheKey(endpoint: string, params: any): string {
  return `${endpoint}:${JSON.stringify(params)}`;
}

export async function cachedRequest<T>(
  endpoint: string,
  requestFn: () => Promise<T>,
  params: any,
): Promise<T> {
  const key = cacheKey(endpoint, params);
  const ttl = CACHE_TTLS[endpoint] ?? 15 * 60 * 1000;
  const cached = cache.get(key);

  if (cached && Date.now() - cached.at < ttl) return cached.data;

  const data = await requestFn();
  cache.set(key, { data, at: Date.now() });
  return data;
}

export function getCacheStats() {
  return { entries: cache.size, sizeBytes: cache.calculatedSize };
}

Step 3: Use Bulk Endpoints Over Single Calls

Apollo's bulk enrichment endpoint handles 10 records per call vs 1. Massive performance gain.

// src/apollo/bulk-ops.ts
import { optimizedClient } from './optimized-client';
import PQueue from 'p-queue';

const queue = new PQueue({ concurrency: 3, intervalCap: 2, interval: 1000 });

// Enrich 100 people: 100 individual calls = 100 requests @ 500ms = 50s
// Batch of 10: 10 bulk calls @ 600ms = 6s (8x faster, same credits)
export async function batchEnrich(
  details: Array<{ email?: string; linkedin_url?: string; first_name?: string; last_name?: string; organization_domain?: string }>,
): Promise<any[]> {
  const results: any[] = [];

  for (let i = 0; i < details.length; i += 10) {
    const batch = details.slice(i, i + 10);
    const result = await queue.add(async () => {
      const { data } = await optimizedClient.post('/people/bulk_match', {
        details: batch,
        reveal_personal_emails: false,
        reveal_phone_number: false,
      });
      return data.matches ?? [];
    });
    results.push(...(result ?? []));
  }

  return results;
}

Step 4: Parallel Search with Concurrency Control

export async function parallelSearch(
  domains: string[],
  concurrency: number = 5,
): Promise<Map<string, any[]>> {
  const searchQueue = new PQueue({ concurrency });
  const results = new Map<string, any[]>();

  await searchQueue.addAll(
    domains.map((domain) => async () => {
      const data = await cachedRequest(
        '/mixed_people/api_search',
        () => optimizedClient.post('/mixed_people/api_search', {
          q_organization_domains_list: [domain],
          person_seniorities: ['vp', 'director', 'c_suite'],
          per_page: 25,
        }).then((r) => r.data),
        { domain },
      );
      results.set(domain, data.people ?? []);
    }),
  );

  return results;
}

Step 5: Slim Response Payloads

Apollo returns large person objects (~2KB each). Extract only needed fields to reduce memory.

interface SlimPerson {
  id: string;
  name: string;
  title: string;
  email?: string;
  company: string;
  seniority: string;
}

function slimPerson(raw: any): SlimPerson {
  return {
    id: raw.id,
    name: raw.name,
    title: raw.title,
    email: raw.email,
    company: raw.organization?.name ?? '',
    seniority: raw.seniority ?? '',
  };
}

// Use immediately after API call to free memory
const { data } = await optimizedClient.post('/mixed_people/api_search', { ... });
const slim = data.people.map(slimPerson);  // ~200 bytes each instead of ~2KB

Step 6: Benchmark Your Endpoints

async function benchmark() {
  const endpoints = [
    { name: 'People Search', fn: () => optimizedClient.post('/mixed_people/api_search',
        { q_organization_domains_list: ['apollo.io'], per_page: 1 }) },
    { name: 'Org Enrich', fn: () => optimizedClient.get('/organizations/enrich',
        { params: { domain: 'apollo.io' } }) },
    { name: 'Auth Health', fn: () => optimizedClient.get('/auth/health') },
  ];

  for (const ep of endpoints) {
    const times: number[] = [];
    for (let i = 0; i < 5; i++) {
      const start = Date.now();
      try { await ep.fn(); } catch {}
      times.push(Date.now() - start);
    }
    const avg = Math.round(times.reduce((a, b) => a + b) / times.length);
    const p95 = times.sort((a, b) => a - b)[Math.floor(times.length * 0.95)];
    console.log(`${ep.name}: avg=${avg}ms, p95=${p95}ms`);
  }
}

Output

  • Connection pooling with keepAlive and configurable maxSockets
  • LRU cache with per-endpoint TTLs (24h org, 4h contact, 15m search)
  • Bulk enrichment via /people/bulk_match (10x fewer requests)
  • Parallel search with p-queue concurrency control
  • Response slimming reducing memory from ~2KB to ~200B per person
  • Benchmarking script measuring avg and p95 latency

Error Handling

IssueResolution
High latencyEnable connection pooling, check for stale cache
Cache missesIncrease TTL for stable data (org enrichment)
Rate limits with parallelismReduce p-queue concurrency
Memory growthLower LRU max entries, slim response payloads

Resources

Next Steps

Proceed to apollo-cost-tuning for cost optimization.

When not to use it

  • When cost optimization is the primary goal

Prerequisites

Valid Apollo API keyNode.js 18+

Limitations

  • Requires manual configuration of TTLs per endpoint
  • Memory usage depends on LRU cache size settings

How it compares

Unlike manual API calls, this approach implements specific infrastructure patterns like connection pooling and automated response slimming to handle Apollo's scale.

Compared to similar skills

apollo-performance-tuning side by side with the closest alternatives in the catalog.

SkillInstallsUpdatedSafetyDifficulty
apollo-performance-tuning (this skill)127dCautionIntermediate
groq-performance-tuning127dNo flagsIntermediate
openrouter-streaming-setup127dReviewIntermediate
ideogram-rate-limits227dReviewIntermediate

Try saying

Example prompts that trigger this skill in your AI assistant.

More by jeremylongshore

View all by jeremylongshore

analyzing-logs

jeremylongshore

Analyze application logs to detect performance issues, identify error patterns, and improve stability by extracting key insights.

14123

ollama-setup

jeremylongshore

Configure auto-configure Ollama when user needs local LLM deployment, free AI alternatives, or wants to eliminate hosted API costs. Trigger phrases: "install ollama", "local AI", "free LLM", "self-hosted AI", "replace OpenAI", "no API costs". Use when appropriate context detected. Trigger with relevant phrases based on skill purpose.

1167

backtesting-trading-strategies

jeremylongshore

Backtest crypto and traditional trading strategies against historical data. Calculates performance metrics (Sharpe, Sortino, max drawdown), generates equity curves, and optimizes strategy parameters. Use when user wants to test a trading strategy, validate signals, or compare approaches. Trigger with phrases like "backtest strategy", "test trading strategy", "historical performance", "simulate trades", "optimize parameters", or "validate signals".

1071

generating-database-seed-data

jeremylongshore

Process this skill enables AI assistant to generate realistic test data and database seed scripts for development and testing environments. it uses faker libraries to create realistic data, maintains relational integrity, and allows configurable data volumes. u... Use when working with databases or data models. Trigger with phrases like 'database', 'query', or 'schema'.

1033

cursor-codebase-indexing

jeremylongshore

Execute set up and optimize Cursor codebase indexing. Triggers on "cursor index setup", "codebase indexing", "index codebase", "cursor semantic search". Use when working with cursor codebase indexing functionality. Trigger with phrases like "cursor codebase indexing", "cursor indexing", "cursor".

885

testing-mobile-apps

jeremylongshore

Execute mobile app testing on iOS and Android devices/simulators. Use when performing specialized testing. Trigger with phrases like "test mobile app", "run iOS tests", or "validate Android functionality".

810

You might also like

groq-performance-tuning

jeremylongshore

Optimize Groq API performance with caching, batching, and connection pooling. Use when experiencing slow API responses, implementing caching strategies, or optimizing request throughput for Groq integrations. Trigger with phrases like "groq performance", "optimize groq", "groq latency", "groq caching", "groq slow", "groq batch".

111

openrouter-streaming-setup

jeremylongshore

Implement streaming responses with OpenRouter. Use when building real-time chat interfaces or reducing time-to-first-token. Trigger with phrases like 'openrouter streaming', 'openrouter sse', 'stream response', 'real-time openrouter'.

111

ideogram-rate-limits

jeremylongshore

Implement Ideogram rate limiting, backoff, and idempotency patterns. Use when handling rate limit errors, implementing retry logic, or optimizing API request throughput for Ideogram. Trigger with phrases like "ideogram rate limit", "ideogram throttling", "ideogram 429", "ideogram retry", "ideogram backoff".

28

firecrawl-reliability-patterns

jeremylongshore

Implement FireCrawl reliability patterns including circuit breakers, idempotency, and graceful degradation. Use when building fault-tolerant FireCrawl integrations, implementing retry strategies, or adding resilience to production FireCrawl services. Trigger with phrases like "firecrawl reliability", "firecrawl circuit breaker", "firecrawl idempotent", "firecrawl resilience", "firecrawl fallback", "firecrawl bulkhead".

36

linear-rate-limits

jeremylongshore

Handle Linear API rate limiting and quotas effectively. Use when dealing with rate limit errors, implementing throttling, or optimizing API usage patterns. Trigger with phrases like "linear rate limit", "linear throttling", "linear API quota", "linear 429 error", "linear request limits".

09

generating-grpc-services

jeremylongshore

Generate gRPC service definitions, stubs, and implementations from Protocol Buffers. Use when creating high-performance gRPC services. Trigger with phrases like "generate gRPC service", "create gRPC API", or "build gRPC server".

13

Search skills

Search the agent skills registry