Skip to main content
The official TypeScript SDK for Poof works in Node.js, Deno, and Bun with full type safety.

Installation

npm install @poof-bg/js
Requirements: Node.js 18+ (or Deno/Bun)

Quick Start

import { Poof } from '@poof-bg/js';
import fs from 'fs/promises';

const poof = new Poof({ apiKey: 'poof_your_api_key' });

const image = await fs.readFile('photo.jpg');
const result = await poof.remove(image);
await fs.writeFile('result.png', result);

Authentication

The SDK looks for your API key in this order:
  1. Passed directly: new Poof({ apiKey: '...' })
  2. Environment variable: POOF_API_KEY
import { Poof } from '@poof-bg/js';

// Option 1: Pass directly
const poof = new Poof({ apiKey: 'poof_your_api_key' });

// Option 2: Use environment variable (recommended)
// POOF_API_KEY=poof_your_api_key
const poof = new Poof();

Usage Examples

From Buffer

import { Poof } from '@poof-bg/js';
import fs from 'fs/promises';

const poof = new Poof();

const image = await fs.readFile('photo.jpg');
const result = await poof.remove(image);
await fs.writeFile('result.png', result);

From File Path (Node.js)

import { Poof } from '@poof-bg/js';
import fs from 'fs/promises';

const poof = new Poof();
const result = await poof.removeFile('photo.jpg');
await fs.writeFile('result.png', result);

From URL

const response = await fetch('https://example.com/photo.jpg');
const image = Buffer.from(await response.arrayBuffer());

const result = await poof.remove(image);

With Options

// White background JPEG
const result = await poof.remove(image, {
  format: 'jpg',
  channels: 'rgb',
  bgColor: '#ffffff',
});

// Small cropped thumbnail
const result = await poof.remove(image, {
  size: 'small',
  crop: true,
});

// WebP for web
const result = await poof.remove(image, {
  format: 'webp',
  size: 'medium',
});

Response Metadata

Access processing metadata from the response:
const response = await poof.removeWithMetadata(image);

console.log(response.data);           // Buffer - the processed image
console.log(response.requestId);      // string - unique request ID
console.log(response.processingTimeMs); // number - processing time
console.log(response.width);          // number - output width
console.log(response.height);         // number - output height

Parallel Processing

import { Poof } from '@poof-bg/js';
import fs from 'fs/promises';
import path from 'path';

const poof = new Poof();

async function processImages(imagePaths: string[]) {
  const results = await Promise.all(
    imagePaths.map(async (imagePath) => {
      const image = await fs.readFile(imagePath);
      const result = await poof.remove(image);
      const outputPath = imagePath.replace(/\.[^.]+$/, '_no_bg.png');
      await fs.writeFile(outputPath, result);
      return outputPath;
    })
  );
  return results;
}

await processImages(['photo1.jpg', 'photo2.jpg', 'photo3.jpg']);

Account Info

Check your credit balance:
const account = await poof.getAccount();

console.log(`Plan: ${account.plan}`);
console.log(`Credits used: ${account.usedCredits}/${account.maxCredits}`);
console.log(`Remaining: ${account.maxCredits - account.usedCredits}`);

Error Handling

import { Poof, PoofError, AuthenticationError, PaymentRequiredError, RateLimitError } from '@poof-bg/js';

const poof = new Poof();

try {
  const result = await poof.remove(image);
} catch (error) {
  if (error instanceof AuthenticationError) {
    console.error('Check your API key');
  } else if (error instanceof PaymentRequiredError) {
    console.error('Out of credits — upgrade your plan');
  } else if (error instanceof RateLimitError) {
    console.error(`Rate limited. Request ID: ${error.requestId}`);
  } else if (error instanceof PoofError) {
    console.error(`API error: ${error.message} (${error.requestId})`);
  } else {
    throw error;
  }
}

Retry with Backoff

async function removeWithRetry(
  poof: Poof,
  image: Buffer,
  maxRetries = 3
): Promise<Buffer> {
  for (let attempt = 0; attempt < maxRetries; attempt++) {
    try {
      return await poof.remove(image);
    } catch (error) {
      if (error instanceof RateLimitError && attempt < maxRetries - 1) {
        const delay = Math.pow(2, attempt) * 1000;
        await new Promise((r) => setTimeout(r, delay));
        continue;
      }
      throw error;
    }
  }
  throw new Error('Max retries exceeded');
}

Configuration

const poof = new Poof({
  apiKey: 'poof_your_api_key',
  baseUrl: 'https://api.poof.bg/v1', // Default
  timeout: 30000, // Request timeout in ms
});

TypeScript Types

Full type definitions are included:
import type { 
  Poof,
  RemoveOptions,
  AccountInfo,
  Format,
  Size,
  Channels,
} from '@poof-bg/js';

const options: RemoveOptions = {
  format: 'png',
  size: 'full',
  crop: false,
};

Framework Examples

Express.js

import express from 'express';
import multer from 'multer';
import { Poof } from '@poof-bg/js';

const app = express();
const upload = multer();
const poof = new Poof();

app.post('/remove-background', upload.single('image'), async (req, res) => {
  if (!req.file) {
    return res.status(400).json({ error: 'No image provided' });
  }

  try {
    const result = await poof.remove(req.file.buffer);
    res.set('Content-Type', 'image/png');
    res.send(result);
  } catch (error) {
    res.status(500).json({ error: 'Processing failed' });
  }
});

app.listen(3000);

Next.js API Route

// app/api/remove-bg/route.ts
import { Poof } from '@poof-bg/js';
import { NextRequest, NextResponse } from 'next/server';

const poof = new Poof();

export async function POST(request: NextRequest) {
  const formData = await request.formData();
  const file = formData.get('image') as File;
  
  if (!file) {
    return NextResponse.json({ error: 'No image' }, { status: 400 });
  }

  const buffer = Buffer.from(await file.arrayBuffer());
  const result = await poof.remove(buffer);
  
  return new NextResponse(result, {
    headers: { 'Content-Type': 'image/png' },
  });
}