Best Buy Async
Submit Best Buy product and discovery jobs asynchronously, then retrieve their results with a snapshot ID.
Use engine=bestbuy_async to collect Best Buy products in the background. You can also use engine=bestbuy&async=true. The API returns a snapshot_id as soon as the submission is accepted. Save it, then retrieve the finished records using the same API key.
Submit a job
Send a POST request to https://ecom.webscrapingapi.com/v1 with api_key, engine=bestbuy_async, and type=product in the query string. Set Content-Type: application/json and send a non-empty JSON array of product inputs. For a single input, GET with the same input fields in the query string is also supported.
Use a Best Buy product url in each input, optionally with all_variations. For keyword discovery, use discover_by=keywords with keywords inputs and omit all_variations. Asynchronous requests accept up to 5000 input objects. The parameter reference lists discovery inputs, limits, and execution options.
These examples require cURL 7.87+, Node.js 18+, Python 3 with requests, PHP with the cURL extension, Go 1.16+, Java 11+, .NET 6+, or Ruby with its standard library, according to the selected tab. Run them on your server and replace YOUR_API_KEY with your WebScrapingAPI key.
API_URL='https://ecom.webscrapingapi.com/v1'
API_KEY="YOUR_API_KEY"
curl --request POST --url "$API_URL" \
--url-query "api_key=$API_KEY" \
--url-query 'engine=bestbuy_async' \
--url-query "type=product" \
--header "Content-Type: application/json" \
--data '[
{
"url": "https://www.bestbuy.com/product/apple-airpods-pro-3-wireless-active-noise-cancelling-earbuds-with-heart-rate-sensing-feature-white/JJGCQLYK5F"
}
]' \
--connect-timeout 30 --max-time 120 --fail-with-bodyconst url = new URL("https://ecom.webscrapingapi.com/v1");
url.search = new URLSearchParams({
"api_key": "YOUR_API_KEY",
"engine": "bestbuy_async",
"type": "product"
}).toString();
const response = await fetch(url, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify([
{
"url": "https://www.bestbuy.com/product/apple-airpods-pro-3-wireless-active-noise-cancelling-earbuds-with-heart-rate-sensing-feature-white/JJGCQLYK5F"
}
]),
signal: AbortSignal.timeout(120_000),
});
if (!response.ok) throw new Error(await response.text());
console.log(JSON.stringify(await response.json(), null, 2));import json
import requests
params = {
"api_key": "YOUR_API_KEY",
"engine": "bestbuy_async",
"type": "product"
}
payload = [
{
"url": "https://www.bestbuy.com/product/apple-airpods-pro-3-wireless-active-noise-cancelling-earbuds-with-heart-rate-sensing-feature-white/JJGCQLYK5F"
}
]
response = requests.post(
"https://ecom.webscrapingapi.com/v1",
params=params,
json=payload,
timeout=(30, 120),
)
response.raise_for_status()
print(json.dumps(response.json(), indent=2))<?php
$params = [
'api_key' => 'YOUR_API_KEY',
'engine' => 'bestbuy_async',
'type' => 'product',
];
$query = http_build_query($params, '', '&', PHP_QUERY_RFC3986);
$ch = curl_init('https://ecom.webscrapingapi.com/v1?' . $query);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CONNECTTIMEOUT => 30,
CURLOPT_TIMEOUT => 120,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
CURLOPT_POSTFIELDS => '[{"url":"https://www.bestbuy.com/product/apple-airpods-pro-3-wireless-active-noise-cancelling-earbuds-with-heart-rate-sensing-feature-white/JJGCQLYK5F"}]',
]);
$response = curl_exec($ch);
if ($response === false) throw new RuntimeException(curl_error($ch));
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($status >= 400) throw new RuntimeException("HTTP $status: $response");
echo $response;package main
import (
"fmt"
"io"
"net/http"
"net/url"
"strings"
"time"
)
func main() {
bestbuy, err := url.Parse("https://ecom.webscrapingapi.com/v1")
if err != nil { panic(err) }
params := url.Values{}
params.Set("api_key", "YOUR_API_KEY")
params.Set("engine", "bestbuy_async")
params.Set("type", "product")
bestbuy.RawQuery = params.Encode()
req, err := http.NewRequest("POST", bestbuy.String(), strings.NewReader("[{\"url\":\"https://www.bestbuy.com/product/apple-airpods-pro-3-wireless-active-noise-cancelling-earbuds-with-heart-rate-sensing-feature-white/JJGCQLYK5F\"}]"))
if err != nil { panic(err) }
req.Header.Set("Content-Type", "application/json")
client := &http.Client{Timeout: 120 * time.Second}
response, err := client.Do(req)
if err != nil { panic(err) }
defer response.Body.Close()
responseBody, err := io.ReadAll(response.Body)
if err != nil { panic(err) }
if response.StatusCode >= 400 { panic(fmt.Sprintf("HTTP %d: %s", response.StatusCode, responseBody)) }
fmt.Println(string(responseBody))
}import java.net.URI;
import java.net.URLEncoder;
import java.net.http.*;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.util.Map;
import java.util.stream.Collectors;
public class Main {
public static void main(String[] args) throws Exception {
Map<String, String> params = Map.of(
"api_key", "YOUR_API_KEY",
"engine", "bestbuy_async",
"type", "product"
);
String query = params.entrySet().stream().map(entry ->
URLEncoder.encode(entry.getKey(), StandardCharsets.UTF_8) + "=" +
URLEncoder.encode(entry.getValue(), StandardCharsets.UTF_8)
).collect(Collectors.joining("&"));
HttpRequest request = HttpRequest.newBuilder(URI.create("https://ecom.webscrapingapi.com/v1?" + query))
.timeout(Duration.ofSeconds(120))
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString("[{\"url\":\"https://www.bestbuy.com/product/apple-airpods-pro-3-wireless-active-noise-cancelling-earbuds-with-heart-rate-sensing-feature-white/JJGCQLYK5F\"}]"))
.build();
HttpClient client = HttpClient.newBuilder().connectTimeout(Duration.ofSeconds(30)).build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
if (response.statusCode() >= 400) throw new RuntimeException("HTTP " + response.statusCode() + ": " + response.body());
System.out.println(response.body());
}
}using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Text;
var parameters = new Dictionary<string, string>
{
["api_key"] = "YOUR_API_KEY",
["engine"] = "bestbuy_async",
["type"] = "product",
};
var url = new UriBuilder("https://ecom.webscrapingapi.com/v1")
{
Query = string.Join("&", parameters.Select(pair =>
$"{Uri.EscapeDataString(pair.Key)}={Uri.EscapeDataString(pair.Value)}")),
};
using var client = new HttpClient { Timeout = TimeSpan.FromSeconds(120) };
using var body = new StringContent("[{\"url\":\"https://www.bestbuy.com/product/apple-airpods-pro-3-wireless-active-noise-cancelling-earbuds-with-heart-rate-sensing-feature-white/JJGCQLYK5F\"}]", Encoding.UTF8, "application/json");
using var response = await client.PostAsync(url.Uri, body);
response.EnsureSuccessStatusCode();
Console.WriteLine(await response.Content.ReadAsStringAsync());require "json"
require "net/http"
require "uri"
uri = URI('https://ecom.webscrapingapi.com/v1')
uri.query = URI.encode_www_form(
api_key: 'YOUR_API_KEY',
engine: 'bestbuy_async',
type: 'product'
)
request = Net::HTTP::Post.new(uri)
request["Content-Type"] = "application/json"
request.body = '[{"url":"https://www.bestbuy.com/product/apple-airpods-pro-3-wireless-active-noise-cancelling-earbuds-with-heart-rate-sensing-feature-white/JJGCQLYK5F"}]'
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = uri.scheme == "https"
http.open_timeout = 30
http.read_timeout = 120
response = http.request(request)
raise "HTTP #{response.code}: #{response.body}" unless response.is_a?(Net::HTTPSuccess)
puts JSON.pretty_generate(JSON.parse(response.body))Submission response
A successful submission returns a snapshot ID. This acknowledges the job; the results may still be processing. This ID is illustrative:
{
"snapshot_id": "s_example_snapshot"
}Save the ID before polling. If a submission times out before returning an ID, the job may already have been accepted. Automatically resending the same submission can create another job and consume additional credits.
Retrieve results
Send GET to the same endpoint with api_key, engine=bestbuy, type=snapshot, and snapshot_id. Replace YOUR_SNAPSHOT_ID with the returned ID and omit the request body.
Use type=progress to check job status without downloading the results. The shared polling route with only api_key and snapshot_id is also available. Polling consumes zero additional request credits.
These retrieval requests also recover an accepted synchronous job after HTTP 504 with error_code=bestbuy_sync_timeout. Its snapshot_id identifies the job that is already running. Submissions initially use one credit per input. Confirmed failed inputs are refunded automatically after completion, including partial refunds for mixed batches, even if you do not retrieve the job. Retrieving the job adds no credits. Do not resubmit the original product request.
API_URL='https://ecom.webscrapingapi.com/v1'
API_KEY="YOUR_API_KEY"
SNAPSHOT_ID="YOUR_SNAPSHOT_ID"
curl --request GET --url "$API_URL" \
--url-query "api_key=$API_KEY" \
--url-query 'engine=bestbuy' \
--url-query 'type=snapshot' \
--url-query "snapshot_id=$SNAPSHOT_ID" \
--connect-timeout 30 --max-time 120 --fail-with-bodyconst url = new URL("https://ecom.webscrapingapi.com/v1");
url.search = new URLSearchParams({
"api_key": "YOUR_API_KEY",
"engine": "bestbuy",
"type": "snapshot",
"snapshot_id": "YOUR_SNAPSHOT_ID"
}).toString();
const response = await fetch(url, {
method: "GET",
signal: AbortSignal.timeout(120_000),
});
if (!response.ok) throw new Error(await response.text());
console.log(JSON.stringify(await response.json(), null, 2));import json
import requests
params = {
"api_key": "YOUR_API_KEY",
"engine": "bestbuy",
"type": "snapshot",
"snapshot_id": "YOUR_SNAPSHOT_ID"
}
response = requests.get(
"https://ecom.webscrapingapi.com/v1",
params=params,
timeout=(30, 120),
)
response.raise_for_status()
print(json.dumps(response.json(), indent=2))<?php
$params = [
'api_key' => 'YOUR_API_KEY',
'engine' => 'bestbuy',
'type' => 'snapshot',
'snapshot_id' => 'YOUR_SNAPSHOT_ID',
];
$query = http_build_query($params, '', '&', PHP_QUERY_RFC3986);
$ch = curl_init('https://ecom.webscrapingapi.com/v1?' . $query);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CONNECTTIMEOUT => 30,
CURLOPT_TIMEOUT => 120,
]);
$response = curl_exec($ch);
if ($response === false) throw new RuntimeException(curl_error($ch));
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($status >= 400) throw new RuntimeException("HTTP $status: $response");
echo $response;package main
import (
"fmt"
"io"
"net/http"
"net/url"
"time"
)
func main() {
bestbuy, err := url.Parse("https://ecom.webscrapingapi.com/v1")
if err != nil { panic(err) }
params := url.Values{}
params.Set("api_key", "YOUR_API_KEY")
params.Set("engine", "bestbuy")
params.Set("type", "snapshot")
params.Set("snapshot_id", "YOUR_SNAPSHOT_ID")
bestbuy.RawQuery = params.Encode()
req, err := http.NewRequest("GET", bestbuy.String(), nil)
if err != nil { panic(err) }
client := &http.Client{Timeout: 120 * time.Second}
response, err := client.Do(req)
if err != nil { panic(err) }
defer response.Body.Close()
responseBody, err := io.ReadAll(response.Body)
if err != nil { panic(err) }
if response.StatusCode >= 400 { panic(fmt.Sprintf("HTTP %d: %s", response.StatusCode, responseBody)) }
fmt.Println(string(responseBody))
}import java.net.URI;
import java.net.URLEncoder;
import java.net.http.*;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.util.Map;
import java.util.stream.Collectors;
public class Main {
public static void main(String[] args) throws Exception {
Map<String, String> params = Map.of(
"api_key", "YOUR_API_KEY",
"engine", "bestbuy",
"type", "snapshot",
"snapshot_id", "YOUR_SNAPSHOT_ID"
);
String query = params.entrySet().stream().map(entry ->
URLEncoder.encode(entry.getKey(), StandardCharsets.UTF_8) + "=" +
URLEncoder.encode(entry.getValue(), StandardCharsets.UTF_8)
).collect(Collectors.joining("&"));
HttpRequest request = HttpRequest.newBuilder(URI.create("https://ecom.webscrapingapi.com/v1?" + query))
.timeout(Duration.ofSeconds(120))
.GET()
.build();
HttpClient client = HttpClient.newBuilder().connectTimeout(Duration.ofSeconds(30)).build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
if (response.statusCode() >= 400) throw new RuntimeException("HTTP " + response.statusCode() + ": " + response.body());
System.out.println(response.body());
}
}using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
var parameters = new Dictionary<string, string>
{
["api_key"] = "YOUR_API_KEY",
["engine"] = "bestbuy",
["type"] = "snapshot",
["snapshot_id"] = "YOUR_SNAPSHOT_ID",
};
var url = new UriBuilder("https://ecom.webscrapingapi.com/v1")
{
Query = string.Join("&", parameters.Select(pair =>
$"{Uri.EscapeDataString(pair.Key)}={Uri.EscapeDataString(pair.Value)}")),
};
using var client = new HttpClient { Timeout = TimeSpan.FromSeconds(120) };
using var response = await client.GetAsync(url.Uri);
response.EnsureSuccessStatusCode();
Console.WriteLine(await response.Content.ReadAsStringAsync());require "json"
require "net/http"
require "uri"
uri = URI('https://ecom.webscrapingapi.com/v1')
uri.query = URI.encode_www_form(
api_key: 'YOUR_API_KEY',
engine: 'bestbuy',
type: 'snapshot',
snapshot_id: 'YOUR_SNAPSHOT_ID'
)
request = Net::HTTP::Get.new(uri)
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = uri.scheme == "https"
http.open_timeout = 30
http.read_timeout = 120
response = http.request(request)
raise "HTTP #{response.code}: #{response.body}" unless response.is_a?(Net::HTTPSuccess)
puts JSON.pretty_generate(JSON.parse(response.body))When the job is still processing, the response contains a running status:
{
"snapshot_id": "s_example_snapshot",
"status": "running"
}Poll again after a short delay, increasing the delay between attempts. Stop polling when results, status=failed, or an error are returned. A progress request returns status=ready when the job is ready to download, or status=failed when it failed, alongside its snapshot_id. Completed records use the same product fields described on the Best Buy Product page. Inspect individual records for errors even when the HTTP request succeeds.
Retrieve completed results promptly and store them in your own system. Keep the API key private and retain access to the Best Buy API while retrieving results.