Skip to main content
When using async operations like /extract/async, /agent/async, or /crawl, you have three flexible options for receiving your results. Choose the method that best fits your infrastructure and workflow.

Polling

Pull results on-demand using task IDs

Callbacks

Receive push notifications when tasks complete

Cloud Delivery

Automatic delivery to your S3 or GCS bucket

Option 1: Polling (Pull)

The simplest approach - submit your async request, receive a task ID, and poll for results when ready.
1

Submit async request

Send a request to the async endpoint. You’ll receive a task or crawl ID to track your request.
from nimble_python import Nimble

nimble = Nimble(api_key="YOUR-API-KEY")

response = nimble.extract.async(
    url="https://www.nimbleway.com",
    render=True,
    formats=["html", "markdown"]
)

task_id = response.task_id
print(f"Task submitted: {task_id}")
2

Check status

Poll the status endpoint to monitor progress.
import time

while True:
    my_task = nimble.tasks.status(task_id)
    print(f"Status: {my_task.task.state}")

    if my_task.state == "success":
        break
    elif my_task.state == "failed":
        print(f"Task failed: {status.error}")
        break

    time.sleep(15)
3

Retrieve results

Once complete, fetch the full results.
results = nimble.tasks.results(task_id)

print(f"HTML length: {len(results.data.html)}")
print(f"Markdown length: {len(results.data.markdown)}")
{
    "url": "https://www.nimbleway.com/blog/post",
    "task_id": "ec89b1f7-1cf2-40eb-91b4-78716093f9ed",
    "status": "success",
    "task": {
        "id": "ec89b1f7-1cf2-40eb-91b4-78716093f9ed",
        "state": "success",
        "created_at": "2026-02-09T23:15:43.549Z",
        "modified_at": "2026-02-09T23:16:39.094Z",
        "account_name": "your-account"
    },
    "data": {
        "html": "<!DOCTYPE html>...",
        "markdown": "# Page Title\n\nContent...",
        "headers": { ... }
    },
    "metadata": {
        "query_time": "2026-02-09T23:15:43.549Z",
        "query_duration": 1877,
        "response_parameters": {
            "input_url": "https://www.nimbleway.com/blog/post"
        },
		"driver": "vx6"
    },
    "status_code": 200
}

Polling endpoints reference

APISubmitCheck StatusGet Results
ExtractPOST /v1/extract/asyncGET /v1/tasks/{task_id}GET /v1/tasks/{task_id}/results
AgentPOST /v1/agent/asyncGET /v1/tasks/{task_id}GET /v1/tasks/{task_id}/results
CrawlPOST /v1/crawlGET /v1/crawl/{crawl_id}GET /v1/tasks/{task_id}/results (per page)

Option 2: Webhooks (Push)

Get notified automatically when your tasks complete. Perfect for event-driven architectures.
1

Submit request with callback URL

Include callback_url (or callback object for crawl) in your async request.
from nimble_python import Nimble

nimble = Nimble(api_key="YOUR-API-KEY")

response = nimble.extract.async(
    url="https://www.nimbleway.com",
    render=True,
    formats=["html", "markdown"],
    callback_url="https://your-server.com/webhooks/nimble"
)

task_id = response.task_id
print(f"Task submitted: {task_id}")
print("Results will be POSTed to your callback URL when ready")
2

Receive webhook notification

Nimble sends a POST to your callback URL when complete:
{
  "task": {
    "id": "8e8cfde8-345b-42b8-b3e2-0c61eb11e00f",
    "state": "success",
    "api_type": "extract",
    "download_url": "https://sdk.nimbleway.com/v1/tasks/8e8cfde8-345b-42b8-b3e2-0c61eb11e00f/results"
  }
}

Webhook configuration options

APIParameterTypeDescription
Extractcallback_urlstringYour callback URL
Agentparams.callback_urlstringYour callback URL
Crawlcallback.urlstringYour callback URL
callback.headersobjectCustom headers for authentication
callback.metadataobjectCustom data included in payload
callback.eventsarrayFilter events: started, page, completed, failed

Option 3: Cloud Delivery

Automatically deliver results directly to your cloud storage bucket.

Amazon S3

Deliver to any S3 bucket in your AWS account

Google Cloud Storage

Deliver to any GCS bucket in your GCP project
1

Configure bucket permissions (one-time)

Grant Nimble’s service account write access to your bucket.
Nimble Service User ARN:
arn:aws:iam::744254827463:user/webit-uploader
Add this bucket policy:
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "NimbleCloudDelivery",
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::744254827463:user/webit-uploader"
      },
      "Action": [
        "s3:PutObject",
        "s3:PutObjectACL",
        "s3:GetBucketLocation"
      ],
      "Resource": [
        "arn:aws:s3:::YOUR_BUCKET_NAME",
        "arn:aws:s3:::YOUR_BUCKET_NAME/*"
      ]
    }
  ]
}
Replace YOUR_BUCKET_NAME with your actual bucket name.
For KMS-encrypted buckets, add this to your KMS key policy:
{
  "Sid": "NimbleKMSAccess",
  "Effect": "Allow",
  "Principal": {
    "AWS": "arn:aws:iam::744254827463:user/webit-uploader"
  },
  "Action": [
    "kms:Encrypt",
    "kms:Decrypt",
    "kms:ReEncrypt*",
    "kms:GenerateDataKey*",
    "kms:DescribeKey"
  ],
  "Resource": "*"
}
2

Submit request with storage config

Include storage_type and storage_url in your request.
from nimble_python import Nimble

nimble = Nimble(api_key="YOUR-API-KEY")

response = nimble.extract.async(
    url="https://www.nimbleway.com",
    render=True,
    formats=["html", "markdown"],
    storage_type="s3",
    storage_url="s3://your-bucket/nimble-results/",
    storage_compress=True
)

task_id = response.task_id
print(f"Results will be saved to: s3://your-bucket/nimble-results/{task_id}.json.gz")
3

Results delivered automatically

When complete, results are written to your bucket as {task_id}.json (or .json.gz if compressed).

Cloud delivery parameters

ParameterTypeDescription
storage_types3 | gsCloud provider
storage_urlstringBucket path with prefix (e.g., s3://bucket/prefix/)
storage_compressbooleanEnable GZIP compression
storage_object_namestringCustom filename (default: task ID)

Comparison

FeaturePollingWebhooksCloud Delivery
Setup complexityNoneRequires endpointRequires bucket setup
Real-time notificationsNo (you poll)YesNo
Automatic storageNoNoYes
Best forSimple integrations, testingEvent-driven appsData pipelines ETLs
Infrastructure neededNoneWeb serverCloud storage bucket

Combining methods

You can combine delivery methods for redundancy:
from nimble_python import Nimble

nimble = Nimble(api_key="YOUR-API-KEY")

# Receive webhook AND store in S3
response = nimble.extract_async(
    url="https://www.nimbleway.com",
    formats=["html", "markdown"],
    callback_url="https://your-server.com/webhooks/nimble",
    storage_type="s3",
    storage_url="s3://your-bucket/results/"
)

Best Practices

  • Check status first - Use /tasks/{id} before fetching full results
  • Use reasonable intervals - Poll every 2-5 seconds, not continuously
  • Handle rate limits - Implement retry logic for 429 responses
  • Set timeouts - Most tasks complete within seconds to minutes
  • Use HTTPS - Always use secure endpoints
  • Verify authenticity - Use custom headers for authentication
  • Respond quickly - Return 200 OK immediately, process async
  • Handle retries - Nimble retries failed deliveries
  • Use prefixes - Organize by date, project, or type
  • Enable compression - Use storage_compress: true for large files
  • Set lifecycle policies - Auto-delete old files to manage costs
  • Use custom names - storage_object_name for meaningful filenames

Next Steps