Amazon Scraper API vs Proxy: Choose a Product Data Source
Compare seller APIs, licensed Amazon product data and proxy page checks by record, access scope and reuse rights.
Read guideRoute Go net/http through an explicit proxy, keep credentials out of logs, cap response work, and separate proxy failures from target responses.

Quick answer: assign an explicit proxy function to Go's Hypertext Transfer Protocol (HTTP) transport, http.Transport, then use a bounded http.Client and validate the response body. For HTTPS, a proxy CONNECT challenge can surface as a transport error before Go returns an HTTP response.
Save the complete example as main.go. Set PROXY_URL to the endpoint without user information. The program inserts a supplied PROXY_USER and PROXY_PASSWORD into proxy authentication in memory; the client sends them to the proxy, not the target. Set both variables together when authentication is required. The defaults use https://example.com/ and Example Domain; TARGET_URL and EXPECTED_MARKER allow an authorized test target. Run go run main.go. The example makes one request and does not retry errors.
Warning: Send one bounded request to a permitted test target and confirm its status and expected content before enabling production jobs. With Basic proxy authentication and an http:// proxy URL, credentials cross the client-to-proxy hop without TLS. CONNECT only establishes the tunnel; TLS to the target encrypts application traffic carried inside it, not the earlier proxy login. Go supports an https:// proxy URL for TLS to the proxy; use it only when the endpoint supports TLS and its certificate validates. Keep credentials in a secret manager or runtime binding, rotate them if exposed, and check account usage after unexpected traffic.
http.ProxyURL creates a proxy function for a fixed URL. The transport uses that function for HTTP requests and for an HTTPS target reached through CONNECT. Go also supports proxy selection from HTTP_PROXY, HTTPS_PROXY, and NO_PROXY through ProxyFromEnvironment, but an explicit URL makes this one request's route visible in code.
The baseline uses only the standard library and was tested with Go 1.27.1. The standard net/http.Transport accepts https:// proxy URLs to protect the client-to-proxy hop; the example's PROXY_URL can use either http:// or https:// with the corresponding endpoint port. It expects these environment bindings:
PROXY_URL=http://proxy.example:3128
PROXY_USER=<PROXY_USER>
PROXY_PASSWORD=<PROXY_PASSWORD>
Keep the URL scheme, host, and port in PROXY_URL. Set these uppercase environment variables from a secret store or process environment. Do not put user:password@ in a shared configuration value.
Save this as main.go. The transport bounds connection setup at 5 seconds and TLS/header phases at 10 seconds; the client timeout is 15 seconds (timeout guide). The target check accepts only 200 OK, while a CONNECT 407 appears as a transport error in the tested Go version:
package main
import (
"context"
"fmt"
"io"
"net"
"net/http"
"net/url"
"os"
"strings"
"time"
)
const maxBodyBytes = int64(1 << 20)
func requiredEnv(name string) string {
value := strings.TrimSpace(os.Getenv(name))
if value == "" {
panic("missing required environment binding: " + name)
}
return value
}
func readBody(response *http.Response) (string, error) {
defer response.Body.Close()
body, err := io.ReadAll(io.LimitReader(response.Body, maxBodyBytes+1))
if err != nil {
return "", err
}
if int64(len(body)) > maxBodyBytes {
return "", fmt.Errorf("response body exceeded local cap")
}
return string(body), nil
}
func main() {
proxyURL, err := url.Parse(requiredEnv("PROXY_URL"))
if err != nil || proxyURL.Host == "" || proxyURL.User != nil || (proxyURL.Scheme != "http" && proxyURL.Scheme != "https") {
panic("PROXY_URL must use an HTTP or HTTPS scheme, host, and no credentials")
}
proxyUser, hasUser := os.LookupEnv("PROXY_USER")
proxyPassword, hasPassword := os.LookupEnv("PROXY_PASSWORD")
if hasUser != hasPassword || (hasUser && (proxyUser == "" || proxyPassword == "")) {
panic("PROXY_USER and PROXY_PASSWORD must be supplied together and non-empty")
}
if hasUser {
proxyURL.User = url.UserPassword(proxyUser, proxyPassword)
}
transport := &http.Transport{
Proxy: http.ProxyURL(proxyURL),
DialContext: (&net.Dialer{Timeout: 5 * time.Second}).DialContext,
TLSHandshakeTimeout: 10 * time.Second,
ResponseHeaderTimeout: 10 * time.Second,
MaxIdleConns: 8,
MaxIdleConnsPerHost: 4,
}
defer transport.CloseIdleConnections()
client := &http.Client{
Transport: transport,
Timeout: 15 * time.Second,
CheckRedirect: func(_ *http.Request, _ []*http.Request) error {
return http.ErrUseLastResponse
},
}
target := os.Getenv("TARGET_URL")
if target == "" {
target = "https://example.com/"
}
expectedMarker := os.Getenv("EXPECTED_MARKER")
if expectedMarker == "" {
expectedMarker = "Example Domain"
}
targetURL, err := url.Parse(target)
if err != nil || targetURL.Host == "" || targetURL.User != nil || (targetURL.Scheme != "http" && targetURL.Scheme != "https") {
panic("TARGET_URL must be an HTTP or HTTPS URL without credentials")
}
request, err := http.NewRequestWithContext(
context.Background(),
http.MethodGet,
target,
nil,
)
if err != nil {
panic("request configuration failed")
}
response, err := client.Do(request)
if err != nil {
panic("request failed in transport or proxy negotiation")
}
status := response.StatusCode
body, bodyErr := readBody(response)
if bodyErr != nil {
panic("response body failed local acceptance checks")
}
if status != http.StatusOK {
panic("target returned a non-accepted HTTP status")
}
if !strings.Contains(body, expectedMarker) {
panic("target marker was absent")
}
fmt.Printf("status=%d marker=present\n", status)
}
Expected output for a successful response:
status=200 marker=present
The Client.Timeout covers connection, redirects, and body reading. The transport timeouts give the failure a more useful phase, while CloseIdleConnections releases pooled sockets when this short-lived program exits. In a worker, reuse one configured client and transport for a bounded unit of work instead of creating a transport per request.
This example makes one attempt. For an idempotent GET, add retries only after classifying the failure, honoring a valid Retry-After rate-limit instruction, and setting a job-level deadline. Do not retry transport, TLS, configuration, or proxy-authentication failures without correcting the cause. With Go 1.27.1, an HTTPS CONNECT 407 returned an error from Client.Do before a response object. The standalone program uses panic to keep this short example's failure paths visible, but production handlers should return a classified error to the application boundary and decide there whether to retry; do not log proxy URLs, credentials, or raw transport errors. Do not copy retries to a request with side effects.
The example accepts one result only when all three checks pass:
input: permitted target URL + expected marker + explicit proxy binding
output: status=200, marker present, body <= 1 MiB
status=200 is an HTTP result, not proof that the record required by the application is present. The marker is intentionally simple; replace it with the field, schema, or checksum required by the job. The body cap is an application bound, not a proxy-account quota. To verify the exit IP, send a request through the same http.Client to a trusted IP-check endpoint with no target credentials. Compare the response with the assigned exit IP; this checks only the request path to that endpoint.
| Observation | Boundary | Next decision |
|---|---|---|
PROXY_URL rejected before a request |
Local configuration | Check scheme, host, port, and secret binding without printing values |
| Transport error or CONNECT failure | Client to proxy or tunnel | Check reachability, proxy protocol, TLS, and proxy credentials; stop before retrying |
407 |
Proxy authentication | Repair proxy auth or entitlement; do not treat it as a target response or keep retrying the same secret |
401 or 403 after a successful tunnel |
Target policy | Check target credentials, permission, or target-side rules |
429 |
Target rate limit | Follow the rate-limit and Retry-After guide and reduce request rate; do not change exits to evade the limit |
| 3xx redirect | Target response | Inspect Location and permit the destination before sending a new request |
| 200 with no marker | Application validation | Reject the record and inspect the target response or parser |
| Body exceeds 1 MiB | Local resource policy | Reject or stream with a job-specific limit; do not silently raise the cap |
For a wider protocol comparison, see HTTP versus SOCKS5 proxies. The curl proxy guide is useful for a hop-by-hop terminal probe.
In the worker, reuse this http.Client and http.Transport for requests in the bounded job, and return classified failures to the job boundary instead of calling panic.
Scale your workflows with the tools you already use. Rotating or sticky sessions up to 72 hours.
Compare seller APIs, licensed Amazon product data and proxy page checks by record, access scope and reuse rights.
Read guideChoose the right anti-detect browser proxy guide, map the shared verification steps, and keep account access separate from the network route.
Read guideOur picks for market research: ProxyLane for small, intermittent projects, plus options for regional tracking, monthly collection and managed extraction.
Read guide