Unflare

repository·main·Indexed 41 days ago

https://github.com/iamyegor/unflare

A Node.js-based proxy service and API designed to bypass Cloudflare anti-bot protection. It uses puppeteer-real-browser to automate the solving of Cloudflare challenges and returns valid session cookies, such as cf_clearance, and browser headers for use in scraping or automation scripts. Version 1.0.0.

Tokens
3.1K
Snippets
12
Records
14
Agent score
52%

What's inside Unflare

  1. What is Unflare and how does it work?

    main

    Unflare is a Node.js API service designed to bypass Cloudflare protection. It uses puppeteer-real-browser to automatically solve Cloudflare challenges.

    Instead of your script interacting with the challenge page directly, you send a request to Unflare. It handles the challenge and returns the necessary cf_clearance token, session cookies, and browser headers. You can then use these returned values in your own subsequent requests to access the target website without being blocked by Cloudflare.

  2. Deploy Unflare using Docker

    main

    The preferred way to run Unflare is via Docker, as the image includes all necessary dependencies (including those required for browser automation).

    Build and Run manually

    Use these commands to build the image locally and run it on port 5002:

    docker build -t unflare .
    docker run -p 5002:5002 unflare

    Use Docker Compose

    You can also use the pre-built image from GitHub Container Registry:

    services:
      unflare:
        image: ghcr.io/iamyegor/unflare
        ports:
          - "5002:5002"
  3. Understand the ServiceResponse structure

    main

    The ServiceResponse<T> class defines a standardized API response format used throughout the service. Every response contains a success flag, a descriptive message, the actual data payload (if any), and an HTTP status code.

    Fields

    • success: A boolean indicating if the operation was successful.
    • message: A string providing context or error details.
    • responseObject: A generic payload of type T. This is typically present in successful responses and may be optional or null in failure scenarios.
    • statusCode: The HTTP status code associated with the response (e.g., 200 for OK, 400 for Bad Request).
  4. Deploy Unflare using Docker Compose

    main

    You can deploy the Unflare service using Docker Compose. By default, the service uses the image ghcr.io/iamyegor/unflare and exposes port 5002 on the host machine.

    services:
      unflare:
        image: ghcr.io/iamyegor/unflare
        ports:
          - "5002:5002"
  5. Scrape a website using JavaScript (Fetch)

    main

    You can integrate Unflare into your JavaScript applications using the fetch API. This example demonstrates how to request cookies and headers for a target URL, including proxy configuration.

    const res = await fetch('http://localhost:5002/scrape', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        url: 'https://example.com',
        timeout: 60000,
        proxy: {
          host: "proxy.example.com",
          port: 8080,
          username: "user",
          password: "pass"
        }
      })
    });
    
    const { cookies, headers } = await res.json();
    // Use cookies/headers for next requests
  6. Use the /scrape API endpoint

    main

    To bypass a Cloudflare challenge, send a POST request to the /scrape endpoint with a JSON body containing the target URL and a timeout.

    Request Body Schema

    FieldTypeRequiredDescription
    urlstringyesTarget URL
    timeoutnumberyesMax time in milliseconds
    methodstringnoHTTP method: "GET" (default) or "POST"
    dataobjectnoForm data for POST requests
    proxyobjectno{ host, port, username, password }

    Successful Response

    On success, the API returns an object containing the session cookies and headers needed to impersonate the solved browser session:

    {
      "cookies": [
        {
          "name": "cf_clearance",
          "value": "abc123...",
          "domain": ".example.com",
          "path": "/",
          "expires": 1676142392.307484,
          "httpOnly": true,
          "secure": true
        }
      ],
      "headers": {
        "user-agent": "Mozilla/5.0..."
      }
    }

    Error Response

    If the process fails, the API returns an error object:

    {
      "code": "error",
      "message": "..."
    }
    curl -X POST http://localhost:5002/scrape \
      -H "Content-Type: application/json" \
      -d '{"url": "https://example.com", "timeout": 60000}'
  7. Configure Unflare via environment variables

    main

    Unflare uses environment variables for configuration, loaded via dotenv based on the NODE_ENV value. The application expects a .env.${NODE_ENV} file. The configuration is validated using envalid and is exported as the env object.

    If running in a non-test environment, the following variables must be provided or will use their respective defaults:

    # Example .env.development file
    NODE_ENV=development
    HOST=0.0.0.0
    PORT=8080
    CORS_ORIGIN=http://localhost:8080
    COMMON_RATE_LIMIT_MAX_REQUESTS=500
    COMMON_RATE_LIMIT_WINDOW_MS=60000
  8. Create ServiceResponse instances

    main

    You can instantiate standardized responses using the static success and failure methods.

    • ServiceResponse.success(message, responseObject, statusCode?): Creates a response with success: true. The statusCode defaults to StatusCodes.OK (200).
    • ServiceResponse.failure(message, responseObject, statusCode?): Creates a response with success: false. The statusCode defaults to StatusCodes.BAD_REQUEST (400).
    import { ServiceResponse } from './path-to-serviceResponse';
    import { StatusCodes } from 'http-status-codes';
    
    // Successful response
    const okResponse = ServiceResponse.success('Operation completed', { id: 123 });
    
    // Failure response with custom status
    const errorResponse = ServiceResponse.failure('Invalid input', null, StatusCodes.UNPROCESSABLE_ENTITY);
  9. Use the scrapeClearance API endpoint

    main

    The scrapeClearance function is an Express-compatible endpoint handler used to bypass Cloudflare challenges and obtain session cookies and headers. It uses puppeteer-real-browser to simulate a real user environment.

    Workflow:

    1. The browser navigates to the provided url using the specified method.
    2. The system waits for the Cloudflare challenge to resolve.
    3. Upon successful navigation (status 200 or 302 matching the target URL), it extracts the browser cookies and specific request headers.
    4. If Cloudflare detects the IP/proxy as blacklisted, it returns a "Blocked by Cloudflare" error.

    Successful Response Structure: The endpoint returns a session object containing:

    • cookies: The cookies obtained from the browser.
    • headers: The request headers (excluding content-type, accept-encoding, accept, and content-length).
    // Example of the expected successful response shape
    {
      "cookies": [...],
      "headers": {
        "user-agent": "...",
        "referer": "..."
      }
    }
  10. Validate ServiceResponse with ServiceResponseSchema

    main

    To validate the structure of a ServiceResponse (for example, when testing or consuming the API), use the ServiceResponseSchema helper. This function takes a Zod schema representing the expected responseObject and returns a Zod object schema for the entire response.

    Note that responseObject is marked as .optional() in the resulting schema.

    import { z } from 'zod';
    import { ServiceResponseSchema } from './path-to-serviceResponse';
    
    const UserSchema = z.object({
      id: z.string(),
      name: z.string(),
    });
    
    // Creates a schema that validates a ServiceResponse containing a User
    const ResponseValidator = ServiceResponseSchema(UserSchema);
    
    const result = ResponseValidator.parse({
      success: true,
      message: 'User found',
      responseObject: { id: '1', name: 'John Doe' },
      statusCode: 200,
    });
  11. Use the scraperRouter for scraping API endpoints

    main

    The scraperRouter is an Express router that exposes endpoints for scraping tasks. Currently, it provides a single POST endpoint /scrape which is handled by the scrapeClearance controller. This router is intended to be mounted within an Express application to enable scraping capabilities.

    import express from 'express';
    import { scraperRouter } from './src/scraperRouter';
    
    const app = express();
    app.use(express.json());
    
    // Mount the scraper router
    app.use('/api', scraperRouter);
    
    app.listen(3000, () => console.log('Scraper API running on port 3000'));
  12. Configure the ScrapeClearance request schema

    main

    To use the scrapeClearance endpoint, you must provide a request body that conforms to the ScrapeClearanceRequestSchema. This schema defines how the scraper navigates to a URL and handles proxies and request methods.

    Request Fields:

    • url (string, required): The target URL to navigate to.
    • timeout (number, optional): The timeout in milliseconds for the operation. Defaults to 60000 if not specified.
    • proxy (object, optional): A proxy configuration object.
    • method (enum, optional): The HTTP method to use. Supported values are "GET" and "POST". Defaults to "GET".
    • data (object, optional): A record of unknown values used for POST requests.
    {
      "url": "https://example.com",
      "timeout": 30000,
      "proxy": {
        "host": "proxy.example.com",
        "port": 8080,
        "username": "user",
        "password": "pass"
      },
      "method": "GET"
    }