Playground Sign in Start free
APIs

Scrape API

Deep dives

Scrape rendered HTML from any website with JavaScript execution. The API uses a headless Chrome browser to render pages and return the final HTML.

Authentication

All API requests require authentication using an API key. Include your API key in the request header.

INFO — Get your API key

Sign up for a free account to receive your API key instantly at ujeebu.com/signup.

Header Format

GET ApiKey: YOUR_API_KEY

Basic Request

Make a simple scraping request by sending a GET or POST request to the endpoint with the target URL.

Endpoint

GET https://api.ujeebu.com/scrape

POST https://api.ujeebu.com/scrape

Code Examples

curl -X GET 'https://api.ujeebu.com/scrape?url=https://example.com&js=true' \
  -H "ApiKey: YOUR_API_KEY"
const response = await fetch('https://api.ujeebu.com/scrape?url=https://example.com&js=true', {
  headers: {
    'ApiKey': 'YOUR_API_KEY'
  }
});

const data = await response.text();
console.log(data);
import { UjeebuClient } from '@ujeebu-org/ujeebu-sdk';

const client = new UjeebuClient('YOUR_API_KEY');

const response = await client.scrape('https://example.com', {
  js: true
});

console.log(response.data);
import requests

response = requests.get(
    'https://api.ujeebu.com/scrape',
    params={'url': 'https://example.com', 'js': 'true'},
    headers={'ApiKey': 'YOUR_API_KEY'}
)

print(response.text)
from ujeebu_python import UjeebuClient

client = UjeebuClient(api_key='YOUR_API_KEY')

response = client.scrape(
    'https://example.com',
    params={'js': True}
)

print(response.text)
OkHttpClient client = new OkHttpClient();

Request request = new Request.Builder()
  .url("https://api.ujeebu.com/scrape?url=https://example.com&js=true")
  .addHeader("ApiKey", "YOUR_API_KEY")
  .build();

Response response = client.newCall(request).execute();
System.out.println(response.body().string());
<?php

$curl = curl_init();

curl_setopt_array($curl, [
  CURLOPT_URL => 'https://api.ujeebu.com/scrape?url=https://example.com&js=true',
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_HTTPHEADER => [
    'ApiKey: YOUR_API_KEY'
  ],
]);

$response = curl_exec($curl);
curl_close($curl);

echo $response;
package main

import (
	"fmt"
	"io/ioutil"
	"net/http"
)

func main() {
	client := &http.Client{}
	req, _ := http.NewRequest("GET", "https://api.ujeebu.com/scrape?url=https://example.com&js=true", nil)
	req.Header.Add("ApiKey", "YOUR_API_KEY")
	
	res, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()
	
	body, _ := ioutil.ReadAll(res.Body)
	fmt.Println(string(body))
}
package main

import (
	"fmt"
	"log"
	"github.com/ujeebu/ujeebu-go"
)

func main() {
	client, err := ujeebu.NewClient("YOUR_API_KEY")
	if err != nil {
		log.Fatal(err)
	}
	
	result, credits, err := client.Scrape(ujeebu.ScrapeParams{
		URL: "https://example.com",
		JS:  true,
	})
	if err != nil {
		log.Fatal(err)
	}
	
	fmt.Printf("Credits: %d\n", credits)
	fmt.Println(result.HTML)
}

Request Parameters

Parameter Type Required Default Description
url string Yes - URL to render.
response_type string No html Indicates what to return. Possible values are: 'html', 'raw', 'pdf' or 'screenshot'.
json boolean No false When set to true, returns a JSON response instead of raw content as specified by response_type.
useragent string No null Override default headless browser user agent.
cookies string No null Indicates custom cookies to send with request.
timeout number No 60 Maximum number of seconds before request timeout.
js boolean No false Indicates whether to execute JavaScript or not.
js_timeout number No 30 When js is enabled, indicates how many seconds the API should wait for the browser to load the page (navigation timeout).
custom_js base64-string No null JavaScript code to execute in page context when js is enabled.
wait_for string No 0 Indicates number of milliseconds to wait before returning response, a selector to wait for, or custom JavaScript to handle the wait. Needs js to be on.
wait_for_timeout number No 0 Indicates timeout (in seconds) for the wait_for param. If 0 or not set, falls back to the timeout value.
screenshot_fullpage boolean No true When response_type is screenshot, indicates whether to take a screenshot of the full page or just the visible viewport.
screenshot_partial string No null When response_type is screenshot, a valid selector of element to screenshot or json-string with coordinates (x, y, width, height) of the rect to screenshot.
scroll_down boolean No false Indicates whether to scroll down the page or not, this applies only when js is enabled.
scroll_wait number No 100 When scroll_down is enabled, indicates the duration of the wait (in milliseconds) between two scrolls.
progressive_scroll boolean No false Indicates type of scroll. If set to true: progressively scrolls down until page height no longer increases or URL changes. If set to false (default), goes to scroll_to_selector or end of page.
proxy_type string No rotating Indicates type of proxy to use. Possible values: 'rotating', 'advanced', 'premium', 'residential', 'mobile', 'custom'.
proxy_country string No US Country ISO 3166-1 alpha-2 code to proxy from. Valid only when premium proxy type is chosen.
custom_proxy string No null URI for your custom proxy in the following format: scheme://host:port. Applicable and required only if proxy_type=custom.
custom_proxy_username string No null Custom proxy username if applicable.
custom_proxy_password string No null Custom proxy password if applicable.
auto_proxy boolean No false Enable a more advanced proxy by default when rotating proxy is not working. It will move to the next proxy option until it gets the content and will only stop when content is available or none of the options worked. Please note that you are billed only on the top option attempted.
proxy_session alphanumeric No null Alphanumeric identifier with a length between 1 and 16 characters, used to route multiple requests from the same proxy instance. Sessions remain active for 30 minutes.
scroll_callback base64-string No null Defines a JavaScript function with boolean output that determines whether to stop scrolling or not.
scroll_to_selector string No null When scroll_down is enabled, indicates the element to scroll to in each scroll. If null the scroll is performed until the end of the page.
device string No desktop Indicates type of device to use to render page. Possible values: 'desktop', 'mobile'.
window_width number No null Indicates browser viewport width.
window_height number No null Indicates browser viewport height.
block_ads boolean No false Indicates whether to block ads or not.
block_resources boolean No true Indicates whether to block resources (images, css, fonts...) or not. Defaults to false when response_type is screenshot or pdf.
extract_rules json-string No null Defines rules used to extract data from supplied web page.
strip_tags csv-string No null Indicates comma-separated list of tags to remove from page after rendering.
http_method string No GET Indicates the http method (GET, POST, PUT) to use to request the target web page.
post_data string No null Data to forward to target web page in case of POST or PUT http method.
auto_captcha_solve boolean No false Enable automatic CAPTCHA detection and solving using external services. Supports reCAPTCHA v2/v3, hCaptcha, Cloudflare Turnstile, FunCaptcha, GeeTest, and image CAPTCHAs. When enabled, requests automatically use super mode with JavaScript rendering.
auto_captcha_solve_timeout number No 120 Timeout in seconds for CAPTCHA solving. CAPTCHAs typically take 20-60 seconds to solve.

Response Format

The response returned depends on the response_type and json parameters. It can be either a byte array in the case of 'pdf' and 'screenshot', text when response_type='raw' or 'html', or JSON when json=1. response_type possible values are as follows:

  • html: returns the html code of the page . If js = 1 it will first execute JavaScript.

  • raw: returns the source html (or file content if URL is not an HTML page) as received from the URL without running JavaScript. js=1 is ignored.

  • pdf: converts page to PDF and returns the PDF binary data.

    • If the json parameter is set to 'true' a JSON response is returned with the base64 encoded value of the pdf file. e.g.:

      {
        "success": true,
        "screenshot": null,
        "html_source": null,
        "pdf": "JVBERi0xLjQKJeLjz9MKNCAwIG9iaiAKPDwKL1N1YnR5cGUgL0xpbms...",
        "html": null
      }
      
  • screenshot: produces a screenshot of the URL in PNG format and returns the binary data.

    • If screenshot_fullpage is set to 'true', takes a screenshot of the full page. If set to 'false', takes a screenshot of the visible viewport only.

    • If the json parameter is set to 'true', a JSON response is returned with the base64 encoded value of the image file. e.g.:

      {
        "success": true,
        "screenshot": "iVBORw0KGgoAAAANSUhEUgAAA2oAACyOCA...",
        "html_source": null,
        "pdf": null,
        "html": null
      }
      

Error Handling

If an error occurred you will receive a JSON response as follows:

{
  "url": "string",
  "message": "string",
  "error_code": 400,
  "errors": ["string"]
}
Name Type Description
url string Given URL
message string Error message
error_code number HTTP error code
errors [string] List of all errors

Response Codes

Code Billed Meaning Suggestion
200 Yes Successful request -
400 NO Some required parameter is missing (URL) Set missing URL or refer to the request error message
401 NO Missing API-KEY Provide API-KEY
404 YES Provided URL not found Provide a valid URL, or change proxy_type
408 YES Request timeout Increase timeout value, change proxy type or use auto_proxy and/or enable JS
429 NO Too many requests upgrade your plan
500 NO Internal error Try again, and contact us if still unsuccessful

Rate Limits & Credits

Examples

Taking Screenshots with SDK

Capture full-page or viewport screenshots using the SDK helper methods.

# Full-page screenshot (returns JSON with base64 data)
curl -X GET 'https://api.ujeebu.com/scrape?url=https://example.com&response_type=screenshot&json=true&screenshot_fullpage=true' \
  -H "ApiKey: YOUR_API_KEY"

# Viewport screenshot only
curl -X GET 'https://api.ujeebu.com/scrape?url=https://example.com&response_type=screenshot&json=true&screenshot_fullpage=false' \
  -H "ApiKey: YOUR_API_KEY"
const response = await fetch('https://api.ujeebu.com/scrape?url=https://example.com&response_type=screenshot&json=true&screenshot_fullpage=true', {
  headers: {
    'ApiKey': 'YOUR_API_KEY'
  }
});

const data = await response.json();
console.log(data.screenshot); // base64-encoded PNG
// Full-page screenshot (returns JSON with base64 data)
const response = await client.getScreenshot('https://example.com', {
  screenshot_fullpage: true
});

console.log(response.data.screenshot); // base64-encoded PNG

// Viewport screenshot only
const viewportResp = await client.getScreenshot('https://example.com', {
  screenshot_fullpage: false
});
import requests

response = requests.get(
    'https://api.ujeebu.com/scrape',
    params={
        'url': 'https://example.com',
        'response_type': 'screenshot',
        'json': 'true',
        'screenshot_fullpage': 'true'
    },
    headers={'ApiKey': 'YOUR_API_KEY'}
)

data = response.json()
print(data['screenshot'])  # base64-encoded PNG
# Full-page screenshot (returns JSON response with base64 data)
response = client.get_screenshot(
    'https://example.com',
    params={'screenshot_fullpage': True}
)

data = response.json()
print(data['screenshot'])  # base64-encoded PNG

# Viewport screenshot only
response = client.get_screenshot(
    'https://example.com',
    params={'screenshot_fullpage': False}
)
OkHttpClient client = new OkHttpClient();

Request request = new Request.Builder()
  .url("https://api.ujeebu.com/scrape?url=https://example.com&response_type=screenshot&json=true&screenshot_fullpage=true")
  .addHeader("ApiKey", "YOUR_API_KEY")
  .build();

Response response = client.newCall(request).execute();
System.out.println(response.body().string());
<?php

$curl = curl_init();

curl_setopt_array($curl, [
  CURLOPT_URL => 'https://api.ujeebu.com/scrape?url=https://example.com&response_type=screenshot&json=true&screenshot_fullpage=true',
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_HTTPHEADER => [
    'ApiKey: YOUR_API_KEY'
  ],
]);

$response = curl_exec($curl);
curl_close($curl);

echo $response;
package main

import (
	"fmt"
	"io/ioutil"
	"net/http"
)

func main() {
	client := &http.Client{}
	req, _ := http.NewRequest("GET", "https://api.ujeebu.com/scrape?url=https://example.com&response_type=screenshot&json=true&screenshot_fullpage=true", nil)
	req.Header.Add("ApiKey", "YOUR_API_KEY")
	
	res, _ := client.Do(req)
	defer res.Body.Close()
	body, _ := ioutil.ReadAll(res.Body)
	fmt.Println(string(body))
}
// Full-page screenshot
screenshotB64, credits, err := client.Screenshot(ujeebu.ScrapeParams{
	URL: "https://example.com",
}, true, "")
if err != nil {
	log.Fatal(err)
}

fmt.Printf("Credits: %d\n", credits)
fmt.Println(screenshotB64) // base64-encoded PNG

// Partial screenshot of a specific element
partialB64, _, err := client.Screenshot(ujeebu.ScrapeParams{
	URL: "https://example.com",
}, false, ".hero-section")

Generating PDFs with SDK

Convert web pages to PDF documents using SDK helper methods.

curl -X GET 'https://api.ujeebu.com/scrape?url=https://example.com/article&response_type=pdf&json=true' \
  -H "ApiKey: YOUR_API_KEY"
const response = await fetch('https://api.ujeebu.com/scrape?url=https://example.com/article&response_type=pdf&json=true', {
  headers: {
    'ApiKey': 'YOUR_API_KEY'
  }
});

const data = await response.json();
console.log(data.pdf); // base64-encoded PDF
const response = await client.getPdf('https://example.com/article');

// response.data.pdf contains base64-encoded PDF
console.log(response.data.pdf);
import requests

response = requests.get(
    'https://api.ujeebu.com/scrape',
    params={
        'url': 'https://example.com/article',
        'response_type': 'pdf',
        'json': 'true'
    },
    headers={'ApiKey': 'YOUR_API_KEY'}
)

data = response.json()
print(data['pdf'])  # base64-encoded PDF
response = client.get_pdf('https://example.com/article')

data = response.json()
# data['pdf'] contains base64-encoded PDF
print('PDF retrieved successfully')
OkHttpClient client = new OkHttpClient();

Request request = new Request.Builder()
  .url("https://api.ujeebu.com/scrape?url=https://example.com/article&response_type=pdf&json=true")
  .addHeader("ApiKey", "YOUR_API_KEY")
  .build();

Response response = client.newCall(request).execute();
System.out.println(response.body().string());
<?php

$curl = curl_init();

curl_setopt_array($curl, [
  CURLOPT_URL => 'https://api.ujeebu.com/scrape?url=https://example.com/article&response_type=pdf&json=true',
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_HTTPHEADER => [
    'ApiKey: YOUR_API_KEY'
  ],
]);

$response = curl_exec($curl);
curl_close($curl);

echo $response;
package main

import (
	"fmt"
	"io/ioutil"
	"net/http"
)

func main() {
	client := &http.Client{}
	req, _ := http.NewRequest("GET", "https://api.ujeebu.com/scrape?url=https://example.com/article&response_type=pdf&json=true", nil)
	req.Header.Add("ApiKey", "YOUR_API_KEY")
	
	res, _ := client.Do(req)
	defer res.Body.Close()
	body, _ := ioutil.ReadAll(res.Body)
	fmt.Println(string(body))
}
pdfB64, credits, err := client.PDF(ujeebu.ScrapeParams{
	URL: "https://example.com/article",
})
if err != nil {
	log.Fatal(err)
}

fmt.Printf("Credits: %d\n", credits)
fmt.Println(pdfB64) // base64-encoded PDF

Using Extract Rules with SDK

Scrape structured data using CSS selectors with SDK helper methods.

curl -X POST 'https://api.ujeebu.com/scrape' \
  -H "ApiKey: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com/product",
    "extract_rules": {
      "title": "h1.product-title",
      "price": ".price-current",
      "description": ".product-description",
      "images": ["img.product-image@src"]
    }
  }'
const response = await fetch('https://api.ujeebu.com/scrape', {
  method: 'POST',
  headers: {
    'ApiKey': 'YOUR_API_KEY',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    url: 'https://example.com/product',
    extract_rules: {
      title: 'h1.product-title',
      price: '.price-current',
      description: '.product-description',
      images: ['img.product-image@src']
    }
  })
});

const data = await response.json();
console.log(data.result);
const rules = {
  title: 'h1.product-title',
  price: '.price-current',
  description: '.product-description',
  images: ['img.product-image@src']
};

const response = await client.scrapeWithRules(
  'https://example.com/product',
  rules
);

console.log(response.data.result);
// { title: '...', price: '...', description: '...', images: [...] }
import requests
import json

response = requests.post(
    'https://api.ujeebu.com/scrape',
    headers={
        'ApiKey': 'YOUR_API_KEY',
        'Content-Type': 'application/json'
    },
    data=json.dumps({
        'url': 'https://example.com/product',
        'extract_rules': {
            'title': 'h1.product-title',
            'price': '.price-current',
            'description': '.product-description',
            'images': ['img.product-image@src']
        }
    })
)

data = response.json()
print(data['result'])
rules = {
    'title': 'h1.product-title',
    'price': '.price-current',
    'description': '.product-description',
    'images': ['img.product-image@src']
}

response = client.scrape_with_rules(
    'https://example.com/product',
    extract_rules=rules
)

data = response.json()
print(data['result'])
# {'title': '...', 'price': '...', 'description': '...', 'images': [...]}
OkHttpClient client = new OkHttpClient();

MediaType JSON = MediaType.parse("application/json");
String body = "{\"url\":\"https://example.com/product\"," +
  "\"extract_rules\":{" +
  "\"title\":\"h1.product-title\"," +
  "\"price\":\".price-current\"," +
  "\"description\":\".product-description\"," +
  "\"images\":[\"img.product-image@src\"]}}";

Request request = new Request.Builder()
  .url("https://api.ujeebu.com/scrape")
  .addHeader("ApiKey", "YOUR_API_KEY")
  .post(RequestBody.create(body, JSON))
  .build();

Response response = client.newCall(request).execute();
System.out.println(response.body().string());
<?php

$curl = curl_init();

$data = json_encode([
  'url' => 'https://example.com/product',
  'extract_rules' => [
    'title' => 'h1.product-title',
    'price' => '.price-current',
    'description' => '.product-description',
    'images' => ['img.product-image@src']
  ]
]);

curl_setopt_array($curl, [
  CURLOPT_URL => 'https://api.ujeebu.com/scrape',
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_POST => true,
  CURLOPT_POSTFIELDS => $data,
  CURLOPT_HTTPHEADER => [
    'ApiKey: YOUR_API_KEY',
    'Content-Type: application/json'
  ],
]);

$response = curl_exec($curl);
curl_close($curl);

echo $response;
package main

import (
	"fmt"
	"io/ioutil"
	"net/http"
	"strings"
)

func main() {
	body := `{"url":"https://example.com/product","extract_rules":{"title":"h1.product-title","price":".price-current","description":".product-description","images":["img.product-image@src"]}}`
	
	req, _ := http.NewRequest("POST", "https://api.ujeebu.com/scrape", strings.NewReader(body))
	req.Header.Add("ApiKey", "YOUR_API_KEY")
	req.Header.Add("Content-Type", "application/json")
	
	res, _ := (&http.Client{}).Do(req)
	defer res.Body.Close()
	respBody, _ := ioutil.ReadAll(res.Body)
	fmt.Println(string(respBody))
}
rules := map[string]interface{}{
	"title":       "h1.product-title",
	"price":       ".price-current",
	"description": ".product-description",
	"images":      []string{"img.product-image@src"},
}

result, credits, err := client.Scrape(ujeebu.ScrapeParams{
	URL:          "https://example.com/product",
	ExtractRules: rules,
})
if err != nil {
	log.Fatal(err)
}

fmt.Printf("Credits: %d\n", credits)
fmt.Println(result.Result)
// map[title:... price:... description:... images:[...]]

Scraping with Custom JavaScript

Execute custom JavaScript before extracting content.

# Base64 encode: document.querySelector('.load-more').click();
# ZG9jdW1lbnQucXVlcnlTZWxlY3RvcignLmxvYWQtbW9yZScpLmNsaWNrKCk7
curl -X GET 'https://api.ujeebu.com/scrape?url=https://example.com&js=true&custom_js=ZG9jdW1lbnQucXVlcnlTZWxlY3RvcignLmxvYWQtbW9yZScpLmNsaWNrKCk7' \
  -H "ApiKey: YOUR_API_KEY"
const customJS = Buffer.from("document.querySelector('.load-more').click();").toString('base64');

const response = await fetch('https://api.ujeebu.com/scrape?url=https://example.com&js=true&custom_js=' + customJS, {
  headers: {
    'ApiKey': 'YOUR_API_KEY'
  }
});

const data = await response.text();
console.log(data);
const customJS = `
  // Click load more button
  document.querySelector('.load-more').click();
  // Wait for content to load
  await new Promise(r => setTimeout(r, 2000));
`;

const response = await client.scrape('https://example.com', {
  js: true,
  custom_js: Buffer.from(customJS).toString('base64')
});

console.log(response.data);
import requests
import base64

custom_js = base64.b64encode(
    b"document.querySelector('.load-more').click();"
).decode()

response = requests.get(
    'https://api.ujeebu.com/scrape',
    params={
        'url': 'https://example.com',
        'js': 'true',
        'custom_js': custom_js
    },
    headers={'ApiKey': 'YOUR_API_KEY'}
)

print(response.text)
import base64

custom_js = """
// Click load more button
document.querySelector('.load-more').click();
// Wait for content to load
await new Promise(r => setTimeout(r, 2000));
"""

response = client.scrape(
    'https://example.com',
    params={
        'js': True,
        'custom_js': base64.b64encode(custom_js.encode()).decode()
    }
)

print(response.text)
import java.util.Base64;

OkHttpClient client = new OkHttpClient();

String customJs = Base64.getEncoder().encodeToString(
  "document.querySelector('.load-more').click();".getBytes());

Request request = new Request.Builder()
  .url("https://api.ujeebu.com/scrape?url=https://example.com&js=true&custom_js=" + customJs)
  .addHeader("ApiKey", "YOUR_API_KEY")
  .build();

Response response = client.newCall(request).execute();
System.out.println(response.body().string());
<?php

$customJs = base64_encode("document.querySelector('.load-more').click();");

$curl = curl_init();

curl_setopt_array($curl, [
  CURLOPT_URL => 'https://api.ujeebu.com/scrape?url=https://example.com&js=true&custom_js=' . $customJs,
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_HTTPHEADER => [
    'ApiKey: YOUR_API_KEY'
  ],
]);

$response = curl_exec($curl);
curl_close($curl);

echo $response;
package main

import (
	"encoding/base64"
	"fmt"
	"io/ioutil"
	"net/http"
)

func main() {
	customJS := base64.StdEncoding.EncodeToString([]byte("document.querySelector('.load-more').click();"))
	
	client := &http.Client{}
	req, _ := http.NewRequest("GET", "https://api.ujeebu.com/scrape?url=https://example.com&js=true&custom_js="+customJS, nil)
	req.Header.Add("ApiKey", "YOUR_API_KEY")
	
	res, _ := client.Do(req)
	defer res.Body.Close()
	body, _ := ioutil.ReadAll(res.Body)
	fmt.Println(string(body))
}
customJS := `
// Click load more button
document.querySelector('.load-more').click();
// Wait for content to load
await new Promise(r => setTimeout(r, 2000));
`

result, credits, err := client.Scrape(ujeebu.ScrapeParams{
	URL:      "https://example.com",
	JS:       true,
	CustomJS: customJS, // SDK auto-encodes to base64
})
if err != nil {
	log.Fatal(err)
}

fmt.Printf("Credits: %d\n", credits)
fmt.Println(result.HTML)

Waiting for JavaScript to execute

By default, the Scrape API stops when the 'DOMContentLoaded' event is fired, but you can use the wait_for parameter to implement additional waiting logic.

wait_for can take three type of values:

  • an integer: to specify the number of milliseconds the JS engine must wait before returning a response
  • a string CSS selector: the JS engine will wait for the element to appear in the page
  • a base64-string JS callable: the JS engine will try to evaluate the callable which implements its own waiting logic.

The following code is an example of a callable which will wait until the loader .loaderBox is hidden:

{callableExample} {callableExampleBase64}

Note: Make sure to URL-encode the value if you're using GET

Running custom JavaScript

custom_js = string|base64-string

It is sometimes necessary to run custom JavaScript before rendering a page to do things like click a button to load items, or delete unwanted HTML elements etc... You can send custom JavsScript to be executed in the page context as base64-string like in the following example:

// base64 string of 'document.querySelector(".load-more").click()'
custom_js = 'ZG9jdW1lbnQucXVlcnlTZWxlY3RvcigiLmxvYWQtbW9yZSIpLmNsaWNrKCk=';

Note: Make sure to URL-encode the value if you're using GET

Downloading files

When the content type returned by the target URL is not HTML, text or image, the API will download files up to 2MB and return the binary file.

Downloading page as PDF

Set parameter response_type to 'pdf' and json to 'false' (default value) to generate PDF file of an HTML page.

Taking a screenshot

Set parameter response_type to 'screenshot' and json to 'false' (default value) to return the screenshot of an HTML page.


You can take a partial screenshot by setting the parameter screenshot_partial to - A valid selector of the element to screenshot - A valid json string with the following coordinates x, y, width and height to specify the partial to screenshot


Rendering on a mobile device

Set parameter device to the name of the mobile device you would like to emulate. Below is a list of devices we currently support:

List of available mobiles devices
  • Blackberry PlayBook
  • Blackberry PlayBook landscape
  • BlackBerry Z30
  • BlackBerry Z30 landscape
  • Galaxy Note 3
  • Galaxy Note 3 landscape
  • Galaxy Note II
  • Galaxy Note II landscape
  • Galaxy S III
  • Galaxy S III landscape
  • Galaxy S5
  • Galaxy S5 landscape
  • iPad
  • iPad landscape
  • iPad Mini
  • iPad Mini landscape
  • iPad Pro
  • iPad Pro landscape
  • iPhone 4
  • iPhone 4 landscape
  • iPhone 5
  • iPhone 5 landscape
  • iPhone 6
  • iPhone 6 landscape
  • iPhone 6 Plus
  • iPhone 6 Plus landscape
  • iPhone 7
  • iPhone 7 landscape
  • iPhone 7 Plus
  • iPhone 7 Plus landscape
  • iPhone 8
  • iPhone 8 landscape
  • iPhone 8 Plus
  • iPhone 8 Plus landscape
  • iPhone SE
  • iPhone SE landscape
  • iPhone X
  • iPhone X landscape
  • iPhone XR
  • iPhone XR landscape
  • JioPhone 2
  • JioPhone 2 landscape
  • Kindle Fire HDX
  • Kindle Fire HDX landscape
  • LG Optimus L70
  • LG Optimus L70 landscape
  • Microsoft Lumia 550
  • Microsoft Lumia 950
  • Microsoft Lumia 950 landscape
  • Nexus 10
  • Nexus 10 landscape
  • Nexus 4
  • Nexus 4 landscape
  • Nexus 5
  • Nexus 5 landscape
  • Nexus 5X
  • Nexus 5X landscape
  • Nexus 6
  • Nexus 6 landscape
  • Nexus 6P
  • Nexus 6P landscape
  • Nexus 7
  • Nexus 7 landscape
  • Nokia Lumia 520
  • Nokia Lumia 520 landscape
  • Nokia N9
  • Nokia N9 landscape
  • Pixel 2
  • Pixel 2 landscape
  • Pixel 2 XL
  • Pixel 2 XL landscape

To use a custom mobile device outside the list above, set parameter device to 'mobile', then specify your custom device viewport dimensions using window_width and window_height.


Removing unwanted elements

Use parameter strip_tags to pass a comma separated list of css selectors of the elements you would like to delete before returning the result. In the example below we remove all 'meta', 'form' and 'input' tags, as well as any elements with class 'hidden':

strip_tags=meta,form,.hidden,input

In the example below we take a screenshot of page 'http://whatsmyuseragent.org/' after removing the div that contains the IP address part:

Using a custom user agent

The Scrape API will by default send its own user agent header (Chrome's headless browser header), but if you want to use a different user agent you need to set parameter useragent:


Passing custom header/cookies

The following will forward headers 'Username' and 'APIKEY' using prefix 'UJB-':

curl -i \
-H 'UJB-Username: ujeebu' \
-H 'UJB-Authorisation: Basic dXNlcm5dhsWU6cGFzc3dvcmQ=' \
-H 'ApiKey: <API Key>' \
-X GET \
https://api.ujeebu.com/scrape?url=https://medium.com/personal-growth/how-to-be-yourself-2221085391a3

To send cookies to a target URL, use parameter cookies to pass a list of semi-colon separated 'CookieName=CookieValue' values. e.g.: Cookie1=Value1;Cookie2=Value2


Transparent Header

when response_type is either html, pdf or screenshot the endpoint will forward all URL headers prefixed with UJB-. when response_type is raw the headers will be forwarded as they are with no prefix.

Using Proxies

Using Ujeebu Scrape with your own proxy

Auto Proxy - Intelligent Proxy Rotation

When dealing with difficult websites that block requests or have aggressive anti-bot measures, use the auto_proxy parameter to automatically try different proxies until one succeeds.

TIP — How Auto Proxy Works

When auto_proxy=true, Ujeebu automatically cycles through available proxy types in sequence. If one proxy fails (network error, timeout, or status ≥ 400), it immediately retries with the next proxy. This continues until a successful response is received or all proxies have been tried.

Retry Flow:

  1. Select proxy → Make request → Check result
  2. On failure (error, timeout, status ≥ 400 except 404) → Try next proxy
  3. On success (status 200-399) → Return response
  4. Final fallback → Direct connection (no proxy)
# Enable auto proxy for difficult sites
curl -X GET 'https://api.ujeebu.com/scrape?url=https://difficult-site.com&auto_proxy=true' \
  -H "ApiKey: YOUR_API_KEY"
curl -X GET 'https://api.ujeebu.com/scrape?url=https://difficult-site.com&auto_proxy=true&js=true' \
  -H "ApiKey: YOUR_API_KEY"
const response = await fetch('https://api.ujeebu.com/scrape?url=https://difficult-site.com&auto_proxy=true&js=true', {
  headers: {
    'ApiKey': 'YOUR_API_KEY'
  }
});

const data = await response.text();
console.log(data);
const response = await client.scrape('https://difficult-site.com', {
  auto_proxy: true,
  js: true  // Combine with JS rendering
});

console.log(response.data);
import requests

response = requests.get(
    'https://api.ujeebu.com/scrape',
    params={
        'url': 'https://difficult-site.com',
        'auto_proxy': 'true',
        'js': 'true'
    },
    headers={'ApiKey': 'YOUR_API_KEY'}
)

print(response.text)
response = client.scrape(
    'https://difficult-site.com',
    params={'auto_proxy': True, 'js': True}
)

print(response.text)
OkHttpClient client = new OkHttpClient();

Request request = new Request.Builder()
  .url("https://api.ujeebu.com/scrape?url=https://difficult-site.com&auto_proxy=true&js=true")
  .addHeader("ApiKey", "YOUR_API_KEY")
  .build();

Response response = client.newCall(request).execute();
System.out.println(response.body().string());
<?php

$curl = curl_init();

curl_setopt_array($curl, [
  CURLOPT_URL => 'https://api.ujeebu.com/scrape?url=https://difficult-site.com&auto_proxy=true&js=true',
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_HTTPHEADER => [
    'ApiKey: YOUR_API_KEY'
  ],
]);

$response = curl_exec($curl);
curl_close($curl);

echo $response;
package main

import (
	"fmt"
	"io/ioutil"
	"net/http"
)

func main() {
	client := &http.Client{}
	req, _ := http.NewRequest("GET", "https://api.ujeebu.com/scrape?url=https://difficult-site.com&auto_proxy=true&js=true", nil)
	req.Header.Add("ApiKey", "YOUR_API_KEY")
	
	res, _ := client.Do(req)
	defer res.Body.Close()
	body, _ := ioutil.ReadAll(res.Body)
	fmt.Println(string(body))
}
result, credits, err := client.Scrape(ujeebu.ScrapeParams{
	URL:       "https://difficult-site.com",
	AutoProxy: true,
	JS:        true,
})
if err != nil {
	log.Fatal(err)
}

fmt.Printf("Credits: %d\n", credits)
fmt.Println(result.HTML)

When to use Auto Proxy:

  • ✅ Scraping sites known to block requests
  • ✅ Handling geo-restricted content
  • ✅ Improving success rates for critical scraping tasks
  • ✅ Avoiding IP bans from aggressive scraping

Important notes:

  • You are billed only for the proxy option that succeeds
  • Each failed attempt still contributes to processing time
  • A 404 response does NOT trigger a retry (it's a valid "not found")

For detailed documentation, see the Auto Proxy Guide.

Route all your request from same proxy instance

To route multiple requests through the same proxy instance (IP), you can give proxy_session a unique identifier. This identifier ensures that all requests with the same proxy_session are directed through the same IP address.

curl -i \
-H 'ApiKey: <API Key>' \
-X GET \
https://api.ujeebu.com/scrape?url=https://ipinfo.io&response_type=raw&proxy_type=premium&proxy_session=bd3400dev9fo

Passing POST/PUT data

You can use parameter http_method to request a web page via either POST or PUT. And if you need to send data in the request body you can use parameter post_data to specify the data to forward.

:::info You can specify the type of forwarded POST/PUT data in post_data by using a custom header:

  • To forward JSON data you can send a valid JSON value in post_data and set header UJB-Content-Type: application/json
  • To forward form data you can send your form encoded data in post_data and set header UJB-Content-Type: application/x-www-form-urlencoded
  • multipart/form-data is not supported ( sending files ) :::

Passing POST data


Response produced by code above:
{`

{ "title": "hello title", "id": 101 } `}

Passing PUT data


Response produced by code above:
{`

{ "title": "put title", "id": 1 } `}

Scrolling down

By default Ujeebu Scrape does not scroll after executing JavaScript.

Set parameter scroll_down to 'true' to scroll to the end of the page before returning a response.

Scroll conditions

The scroll script will continuously scroll until one of the following conditions is satisfied:

  • scroll_callback parameter's function (if provided) return 'false'

    // scroll until the .load-more button disappears
    () => document.querySelector(".load-more") !== null;
    
  • The height of the page doesn't change after two consecutive scrolls

  • The URL of the page changes (this will throw an error, disable scrolling and re-run the scrape request).

Scroll behavior

The API's scroll script will by default scroll down to the end of page, but this behavior can be customized using parameter scroll_to_selector which will define the selector of the element to scroll to.

Parameter scroll_wait defines the time in milliseconds to wait between two scrolls (default = 50)

Blocking Ads

Block ads is disabled by default. To change this, set parameter block_ads to 'true'.

CAPTCHA Solving {#captcha-solving}

The Scrape API can automatically detect and solve CAPTCHAs on web pages using external solving services. This is an opt-in feature that supports:

  • reCAPTCHA v2/v3 (including invisible and enterprise versions)
  • hCaptcha
  • Cloudflare Turnstile
  • FunCaptcha (Arkose Labs)
  • GeeTest
  • Image CAPTCHAs

INFO — How it works

When auto_captcha_solve is enabled, the API automatically detects CAPTCHAs on the page, sends them to a solving service, and injects the solution token back into the page. This happens transparently before returning the response.

Code Example

curl -X GET 'https://api.ujeebu.com/scrape?url=https://example.com/protected&js=true&auto_captcha_solve=true&auto_captcha_solve_timeout=120000' \
  -H "ApiKey: YOUR_API_KEY"
const response = await fetch('https://api.ujeebu.com/scrape?url=https://example.com/protected&js=true&auto_captcha_solve=true&auto_captcha_solve_timeout=120000', {
  headers: {
    'ApiKey': 'YOUR_API_KEY'
  }
});

const data = await response.text();
console.log(data);
const response = await client.scrape('https://example.com/protected', {
  js: true,
  auto_captcha_solve: true,
  auto_captcha_solve_timeout: 120000 // 2 minutes
});

console.log(response.data);
import requests

response = requests.get(
    'https://api.ujeebu.com/scrape',
    params={
        'url': 'https://example.com/protected',
        'js': 'true',
        'auto_captcha_solve': 'true',
        'auto_captcha_solve_timeout': 120000
    },
    headers={'ApiKey': 'YOUR_API_KEY'}
)

print(response.text)
response = client.scrape(
    'https://example.com/protected',
    params={
        'js': True,
        'auto_captcha_solve': True,
        'auto_captcha_solve_timeout': 120000  # 2 minutes
    }
)

print(response.text)
OkHttpClient client = new OkHttpClient();

Request request = new Request.Builder()
  .url("https://api.ujeebu.com/scrape?url=https://example.com/protected&js=true&auto_captcha_solve=true&auto_captcha_solve_timeout=120000")
  .addHeader("ApiKey", "YOUR_API_KEY")
  .build();

Response response = client.newCall(request).execute();
System.out.println(response.body().string());
<?php

$curl = curl_init();

curl_setopt_array($curl, [
  CURLOPT_URL => 'https://api.ujeebu.com/scrape?url=https://example.com/protected&js=true&auto_captcha_solve=true&auto_captcha_solve_timeout=120000',
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_HTTPHEADER => [
    'ApiKey: YOUR_API_KEY'
  ],
]);

$response = curl_exec($curl);
curl_close($curl);

echo $response;
package main

import (
	"fmt"
	"io/ioutil"
	"net/http"
)

func main() {
	client := &http.Client{}
	req, _ := http.NewRequest("GET", "https://api.ujeebu.com/scrape?url=https://example.com/protected&js=true&auto_captcha_solve=true&auto_captcha_solve_timeout=120000", nil)
	req.Header.Add("ApiKey", "YOUR_API_KEY")
	
	res, _ := client.Do(req)
	defer res.Body.Close()
	body, _ := ioutil.ReadAll(res.Body)
	fmt.Println(string(body))
}
result, credits, err := client.Scrape(ujeebu.ScrapeParams{
	URL:                    "https://example.com/protected",
	JS:                     true,
	AutoCaptchaSolve:        true,
	AutoCaptchaSolveTimeout: 120000, // 2 minutes
})
if err != nil {
	log.Fatal(err)
}

fmt.Printf("Credits: %d\n", credits)
fmt.Println(result.HTML)

WARNING — Additional credits

When CAPTCHA is detected and solved, an additional +5 credits surcharge is applied on top of the base request cost.

Returning output as JSON

By default, the API returns a response matching the given response_type parameter:

  • 'pdf' will return 'application/pdf'
  • 'screenshot' will return 'image/png'
  • 'html' and 'raw' will return 'text/html'

If parameter json is set to 'true' the API will return a JSON response in all cases.

Usage Tracking

To track credit usage programmatically, call the /account endpoint. See Account API for the full reference, response shape, and rate limit (10 calls/minute).

Ready to build?

Spin up an API key in 60 seconds

Free tier: 5,000 credits, no card, full access to every endpoint on this page.