TakionAPI
Start a TrialJoin our DiscordBuy a PlanDashboard
  • Takion API
  • Interacting with our APIs
  • Datadome
    • Bypass Solution
    • Example Implementations
    • Common Errors & Troubleshooting
  • Incapsula / Imperva
    • reese84 Bypass Solution
    • ___utmvc Bypass Solution
    • Example Implementations
    • Common Errors & Troubleshooting
  • Perimeter X Mobile
    • Bypass Solution
    • Example Implementations
  • GeeTest
    • v3 Bypass Solution
    • v4 Bypass Solution
    • Example Implementations
  • AWS Cognito
    • Bypass Solution
    • Example Implementations
  • Castle
    • Bypass Solution
    • Example Implementations
  • NuData
    • Bypass Solution
    • Example Implementations
  • Image-to-Text Captchas / OCR
    • Bypass Solution
    • Example Implementations
  • Frameworks & Modules
    • Adyen and riskData
    • Queue-IT Module
Powered by GitBook
On this page

Was this helpful?

  1. Datadome

Example Implementations

When interacting with Datadome a good TLS Client is required

Note that the interstitial challenge will return a json, with other than the cookie, an url to follow. In case of hard-protection mode on datadome, you may get redirected to a captcha challenge that needs to be solved as well

from tls_client import Session
from requests import post

if __name__ == "__main__":
    API_KEY = "TAKION_API_XXXX" 

    session = Session("chrome_120") 
    page_url = 'https://www.footlocker.pt/en/product/~/314206535404.html'
    page_headers = {
        'Host': 'www.footlocker.pt',
        'cache-control': 'max-age=0',
        'sec-ch-device-memory': '8',
        'sec-ch-ua': '"Not/A)Brand";v="8", "Chromium";v="126", "Google Chrome";v="126"',
        'sec-ch-ua-mobile': '?0',
        'sec-ch-ua-arch': '"arm"',
        'sec-ch-ua-platform': '"macOS"',
        'sec-ch-ua-model': '""',
        'sec-ch-ua-full-version-list': '"Not/A)Brand";v="8.0.0.0", "Chromium";v="126.0.6478.127", "Google Chrome";v="126.0.6478.127"',
        'upgrade-insecure-requests': '1',
        'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36',
        'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
        'sec-fetch-site': 'none',
        'sec-fetch-mode': 'navigate',
        'sec-fetch-user': '?1',
        'sec-fetch-dest': 'document',
        'accept-language': 'en-GB,en;q=0.9',
        'priority': 'u=0, i',
    }

    # 1. Load the page
    response = session.get(page_url, headers=page_headers)

    # 2. Check for Datadome
    if not (("geo.captcha-delivery.com" in response.text or \
            "interstitial.captcha-delivery.com" in response.text) \
                and response.status_code == 403): # Check if we need to solve a challenge
        print("Page loaded successfully")
        exit(0)
    
    # 3. Generate challenge url
    response = post(
        "https://datadome.takionapi.tech/build",
        headers={
            "x-api-key": API_KEY,
        },
        json={
            "datadome": session.cookies.get_dict().get("datadome"),
            "referer": page_url,
            "html": response.text
        }
    ).json()

    if response.get("error"):
        print("Task failed with error => %s" % response["error"])
        exit(0)

    challenge_url = response["url"]
    
    # 4. Solve the challenge
    print(f"Solving {response['challenge_type']} challenge...")
    challenge = session.get(
        challenge_url, 
        headers={
            'Host': 'geo.captcha-delivery.com',
            'sec-ch-ua': '"Not/A)Brand";v="8", "Chromium";v="126", "Google Chrome";v="126"',
            'sec-ch-ua-mobile': '?0',
            'sec-ch-ua-platform': '"macOS"',
            'Upgrade-Insecure-Requests': '1',
            'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36',
            'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
            'Sec-Fetch-Site': 'cross-site',
            'Sec-Fetch-Mode': 'navigate',
            'Sec-Fetch-Dest': 'iframe',
            'Referer': 'https://www.footlocker.pt/en/product/~/314206535404.html',
            'Accept-Language': 'en-GB,en;q=0.9',
        }
    )
    data = post(
        f"https://datadome.takionapi.tech/solve",
        headers={
            "x-api-key": API_KEY,
            "User-Agent": 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36',
        },
        json={
            "html": challenge.text
        }
    ).json()
    if error := data.get("error"):
        print("Task failed with error => %s" % error)
        exit(0)

    # 5. Post the solution to Datadome
    print("Posting solution...")
    
    # For interstitial is a POST request, footlocker only uses it
    res = session.post(
        data["url"],
        data=data["payload"],
        headers={
            # Headers took from our browser
            'Host': 'geo.captcha-delivery.com',
            'sec-ch-ua': '"Not/A)Brand";v="8", "Chromium";v="126", "Google Chrome";v="126"',
            'sec-ch-ua-platform': '"macOS"',
            'sec-ch-ua-mobile': '?0',
            'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36',
            'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
            'Accept': '*/*',
            'Sec-Fetch-Site': 'same-origin',
            'Sec-Fetch-Mode': 'cors',
            'Sec-Fetch-Dest': 'empty',
            'Referer': 'https://geo.captcha-delivery.com/captcha/?initialCid=AHrlqAAAAAMAyaXgoxstywMAs2mAaw%3D%3D&hash=EC3B9FB6F2A31D3AF16C270E6531D2&cid=WnaMs0Z7esaErwyCZ5bgStxks4ZNPTM43srPi1nPou7gj6cYdKWPr3WMHkqqO1GS3v8Dnbg5JN4O1l4lMScX9TesXJvvy67uqtRjDIzLM8dap3xjH~zSxlrIZeFcyzaG&t=fe&referer=https%3A%2F%2Feuro2024-sales.tickets.uefa.com%2F&s=43337&e=511a3fab6473017b5c67ee503b9dc67701795c127fc3898022ea13fb22e74965&dm=cd',
            'Accept-Language': 'en-GB,en;q=0.9',
        }
    )
    data = res.json()
    if cookie := data["cookie"].split("datadome=")[1].split("; ")[0]:
        print(f"Got datadome cookie => {cookie[:30]}")
        session.cookies.set("datadome", cookie)
    
    # 6. Load the page again
    response = session.get(page_url, headers=page_headers)
    print(response)
package main

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"log"
	"net/url"
	"strings"

	http "github.com/bogdanfinn/fhttp"

	"github.com/bogdanfinn/fhttp/http2"
	tls_client "github.com/bogdanfinn/tls-client"
	"github.com/bogdanfinn/tls-client/profiles"
	tls "github.com/bogdanfinn/utls"
)

const apiKey = "TAKION_API_XXXX" // Replace with your actual API key

func main() {
	requestWithCustomClient()
}

type DatadomeResponse struct {
	URL     string `json:"url"`
	Payload string `json:"payload"`
	Cookie  string `json:"cookie"`
	Error   string `json:"error"`
}

type CaptchaSolveResponse struct {
	URL     string          `json:"url"`
	Payload json.RawMessage `json:"payload"` // Changed to RawMessage to handle different structures
	Error   string          `json:"error"`
}

type CaptchaSolutionResponse struct {
	Cookie string `json:"cookie"`
}

func requestWithCustomClient() {
	settings := map[http2.SettingID]uint32{
		http2.SettingHeaderTableSize:      65536,
		http2.SettingMaxConcurrentStreams: 1000,
		http2.SettingInitialWindowSize:    6291456,
		http2.SettingMaxHeaderListSize:    262144,
	}
	settingsOrder := []http2.SettingID{
		http2.SettingHeaderTableSize,
		http2.SettingMaxConcurrentStreams,
		http2.SettingInitialWindowSize,
		http2.SettingMaxHeaderListSize,
	}

	pseudoHeaderOrder := []string{
		":method",
		":authority",
		":scheme",
		":path",
	}

	connectionFlow := uint32(15663105)

	specFactory := func() (tls.ClientHelloSpec, error) {
		return tls.ClientHelloSpec{
			CipherSuites: []uint16{
				tls.GREASE_PLACEHOLDER,
				tls.TLS_AES_128_GCM_SHA256,
				tls.TLS_AES_256_GCM_SHA384,
				tls.TLS_CHACHA20_POLY1305_SHA256,
				tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
				tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
				tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
				tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
				tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
				tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
				tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
				tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
				tls.TLS_RSA_WITH_AES_128_GCM_SHA256,
				tls.TLS_RSA_WITH_AES_256_GCM_SHA384,
				tls.TLS_RSA_WITH_AES_128_CBC_SHA,
				tls.TLS_RSA_WITH_AES_256_CBC_SHA,
			},
			CompressionMethods: []uint8{
				tls.CompressionNone,
			},
			Extensions: []tls.TLSExtension{
				&tls.UtlsGREASEExtension{},
				&tls.SNIExtension{},
				&tls.ExtendedMasterSecretExtension{},
				&tls.RenegotiationInfoExtension{Renegotiation: tls.RenegotiateOnceAsClient},
				&tls.SupportedCurvesExtension{Curves: []tls.CurveID{
					tls.CurveID(tls.GREASE_PLACEHOLDER),
					tls.X25519,
					tls.CurveP256,
					tls.CurveP384,
				}},
				&tls.SupportedPointsExtension{SupportedPoints: []byte{
					0,
				}},
				&tls.SessionTicketExtension{},
				&tls.ALPNExtension{AlpnProtocols: []string{"h2", "http/1.1"}},
				&tls.StatusRequestExtension{},
				&tls.SignatureAlgorithmsExtension{SupportedSignatureAlgorithms: []tls.SignatureScheme{
					tls.ECDSAWithP256AndSHA256,
					tls.PSSWithSHA256,
					tls.PKCS1WithSHA256,
					tls.ECDSAWithP384AndSHA384,
					tls.PSSWithSHA384,
					tls.PKCS1WithSHA384,
					tls.PSSWithSHA512,
					tls.PKCS1WithSHA512,
				}},
				&tls.SCTExtension{},
				&tls.KeyShareExtension{KeyShares: []tls.KeyShare{
					{Group: tls.CurveID(tls.GREASE_PLACEHOLDER), Data: []byte{0}},
					{Group: tls.X25519},
				}},
				&tls.PSKKeyExchangeModesExtension{Modes: []uint8{
					tls.PskModeDHE,
				}},
				&tls.SupportedVersionsExtension{Versions: []uint16{
					tls.VersionTLS13,
					tls.VersionTLS12,
					tls.VersionTLS11,
					tls.VersionTLS10,
				}},
				&tls.UtlsCompressCertExtension{Algorithms: []tls.CertCompressionAlgo{
					tls.CertCompressionBrotli,
				}},
				&tls.ApplicationSettingsExtension{SupportedProtocols: []string{"h2"}},
				&tls.UtlsGREASEExtension{},
				&tls.UtlsPaddingExtension{GetPaddingLen: tls.BoringPaddingStyle},
			},
		}, nil
	}

	customClientProfile := profiles.NewClientProfile(tls.ClientHelloID{
		Client:      "MyCustomProfile",
		Version:     "1",
		Seed:        nil,
		SpecFactory: specFactory,
	}, settings, settingsOrder, pseudoHeaderOrder, connectionFlow, nil, nil)

	options := []tls_client.HttpClientOption{
		tls_client.WithTimeoutSeconds(60),
		tls_client.WithClientProfile(customClientProfile), // use custom profile here
	}

	client, err := tls_client.NewHttpClient(tls_client.NewNoopLogger(), options...)
	if err != nil {
		log.Println(err)
		return
	}
	
	// Step 1: Perform the POST request
	diocanurl := "https://mygift.giftcardmall.com/api/card/getCardBalanceSummary"

	data := `{"cardNumber": "4358800457414798","expirationMonth": 7,"expirationYear": 2032,"securityCode": "823","rmsSessionId": "7T1C3BFHYTQJ89RN9KZ0AZ2HG8"}`

	headers := http.Header{
		"Host":               {"mygift.giftcardmall.com"},
		"sec-ch-ua":          {`"Not)A;Brand";v="99", "Google Chrome";v="127", "Chromium";v="127"`},
		"accept":             {"application/json, text/plain, */*"},
		"content-type":       {"application/json"},
		"sourceorigin":       {"https://mygift.giftcardmall.com/"},
		"sec-ch-ua-mobile":   {"?0"},
		"user-agent":         {"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36"},
		"sec-ch-ua-platform": {`"Windows"`},
		"dnt":                {"1"},
		"origin":             {"https://mygift.giftcardmall.com"},
		"sec-fetch-site":     {"same-origin"},
		"sec-fetch-mode":     {"cors"},
		"sec-fetch-dest":     {"empty"},
		"referer":            {"https://mygift.giftcardmall.com/"},
		"accept-language":    {"en-GB,en;q=0.9"},
		"priority":           {"u=1, i"},
		http.HeaderOrderKey: {
			"accept",
			"accept-encoding",
			"accept-language",
			"cache-control",
			"if-none-match",
			"sec-ch-ua",
			"sec-ch-ua-mobile",
			"sec-ch-ua-platform",
			"sec-fetch-dest",
			"sec-fetch-mode",
			"sec-fetch-site",
			"sec-fetch-user",
			"upgrade-insecure-requests",
			"user-agent",
		},
	}

	req, err := http.NewRequest("POST", diocanurl, bytes.NewBuffer([]byte(data)))

	if err != nil {
		log.Println(err)
		return
	}

	req.Header = headers

	resp, err := client.Do(req)
	if err != nil {
		log.Println(err)
		return
	}
	defer resp.Body.Close()

	body, _ := io.ReadAll(resp.Body)
	// Step 2: Check for Datadome
	if resp.StatusCode == 403 && (strings.Contains(string(body), "geo.captcha-delivery.com") || strings.Contains(string(body), "interstitial.captcha-delivery.com")) {
		log.Println("Datadome challenge detected")
		var challenge DatadomeResponse
		if err := json.Unmarshal(body, &challenge); err != nil {
			log.Println("Failed to parse Datadome challenge:", err)
			return
		}

		log.Println(challenge.URL)

		// Step 3: Fetch challenge page
		challengeReq, err := http.NewRequest("GET", challenge.URL, nil)
		if err != nil {
			log.Println(err)
			return
		}

		challengeReq.Header = http.Header{
			"Host":                      {"geo.captcha-delivery.com"},
			"sec-ch-ua":                 {`"Not/A)Brand";v="8", "Chromium";v="126", "Google Chrome";v="126"`},
			"sec-ch-ua-mobile":          {"?0"},
			"sec-ch-ua-platform":        {"\"macOS\""},
			"Upgrade-Insecure-Requests": {"1"},
			"User-Agent":                {"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36"},
			"Accept":                    {"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7"},
			"Sec-Fetch-Site":            {"cross-site"},
			"Sec-Fetch-Mode":            {"navigate"},
			"Sec-Fetch-Dest":            {"iframe"},
			"Referer":                   {"https://www.footlocker.pt/en/product/~/314206535404.html"},
			"Accept-Language":           {"en-GB,en;q=0.9"},
		}

		challengeResp, err := client.Do(challengeReq)
		if err != nil {
			log.Println(err)
			return
		}

		defer challengeResp.Body.Close()

		challengeBody, _ := io.ReadAll(challengeResp.Body)

		htmlBody := string(challengeBody)

		solution_url, solution, err := solveCaptcha(htmlBody)
		if err != nil {
			log.Println("Captcha solving failed:", err)
			return
		}

		formData := url.Values{}

		var solutionMap map[string]interface{}
		err = json.Unmarshal([]byte(solution), &solutionMap)
		if err != nil {
			log.Println(err)
			return
		}

		for key, value := range solutionMap {
			formData.Set(key, fmt.Sprintf("%v", value))
		}

		encodedFormData := formData.Encode()

		solutionReq, err := http.NewRequest("POST", solution_url, strings.NewReader(encodedFormData))
		if err != nil {
			log.Println(err)
			return
		}

		log.Println(solution_url)

		solutionReq.Header = http.Header{
			"Host":                      {"geo.captcha-delivery.com"},
			"sec-ch-ua":                 {`"Not/A)Brand";v="8", "Chromium";v="126", "Google Chrome";v="126"`},
			"sec-ch-ua-mobile":          {"?0"},
			"sec-ch-ua-platform":        {"\"macOS\""},
			"Upgrade-Insecure-Requests": {"1"},
			"User-Agent":                {"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36"},
			"Accept":                    {"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7"},
			"Sec-Fetch-Site":            {"same-origin"},
			"Sec-Fetch-Mode":            {"cors"},
			"Sec-Fetch-Dest":            {"empty"},
			"Referer":                   {challenge.URL},
			"Accept-Language":           {"en-GB,en;q=0.9"},
		}

		solutionResp, err := client.Do(solutionReq)
		if err != nil {
			log.Println(err)
			return
		}
		defer solutionResp.Body.Close()

		solutionBody, _ := io.ReadAll(solutionResp.Body)
		fmt.Println(string(solutionBody))
		fmt.Println(string(solutionResp.Status))

		fmt.Println("Captcha solution posted, response:", string(solutionBody))

		var solutionCookie CaptchaSolutionResponse
		err = json.Unmarshal([]byte(solutionBody), &solutionCookie)
		if err != nil {
			log.Fatalf("Failed to parse captcha solution response: %v", err)
		}

		cookieParts := strings.Split(solutionCookie.Cookie, ";")
		datadomeCookie := cookieParts[0]

		// Log the cookie for verification
		fmt.Printf("Extracted Cookie: %s\n", datadomeCookie)

		req.Header.Set("Cookie", datadomeCookie)

		req, err := http.NewRequest("POST", diocanurl, bytes.NewBuffer([]byte(data)))

		if err != nil {
			log.Println(err)
			return
		}

		req.Header = headers

		retryResp, err := client.Do(req)
		if err != nil {
			log.Println(err)
			return
		}
		defer retryResp.Body.Close()

		retryBody, _ := io.ReadAll(retryResp.Body)
		fmt.Println("Page reloaded successfully", string(retryBody))
	} else {
		fmt.Println("Page loaded successfully", string(body))
	}
}

func solveCaptcha(html string) (string, string, error) {
	// Define the solve API URL
	solveURL := "https://datadome.takionapi.tech/solve"

	// Create the payload with the HTML string
	payload := map[string]string{
		"html": html,
	}

	// Serialize the payload to JSON
	payloadBytes, err := json.Marshal(payload)
	if err != nil {
		return "", "", fmt.Errorf("failed to marshal payload: %v", err)
	}

	// Create the POST request to the captcha-solving service
	req, err := http.NewRequest(http.MethodPost, solveURL, bytes.NewBuffer(payloadBytes))
	if err != nil {
		return "", "", fmt.Errorf("failed to create request: %v", err)
	}

	// Set the required headers
	req.Header.Set("x-api-key", apiKey) // Replace with your actual API key
	req.Header.Set("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36")
	req.Header.Set("Content-Type", "application/json")

	// Send the request
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		return "", "", fmt.Errorf("failed to send request: %v", err)
	}
	defer resp.Body.Close()

	// Check if the API returns a 500 status code
	if resp.StatusCode == 500 {
		return "", "", errors.New("API returned status code 500")
	}

	// Read the response body
	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return "", "", fmt.Errorf("failed to read response body: %v", err)
	}

	// Parse the response JSON into a struct
	var solveResp CaptchaSolveResponse
	if err := json.Unmarshal(body, &solveResp); err != nil {
		return "", "", fmt.Errorf("failed to unmarshal response: %v", err)
	}

	// Check if there's an error in the API response
	if solveResp.Error != "" {
		return "", "", fmt.Errorf("captcha solving error: %s", solveResp.Error)
	}

	// Convert the RawMessage Payload to a string
	var payloadString string
	if err := json.Unmarshal(solveResp.Payload, &payloadString); err != nil {
		// Handle case where payload is not a simple string
		log.Println("Payload is not a string, trying to handle as a JSON object")

		// If payload is not a string, try unmarshaling it into a more generic map
		var payloadObject map[string]interface{}
		if err := json.Unmarshal(solveResp.Payload, &payloadObject); err != nil {
			return "", "", fmt.Errorf("failed to unmarshal payload as JSON object: %v", err)
		}

		// Return the entire JSON object as a string (or you can handle specific fields here)
		payloadBytes, err := json.MarshalIndent(payloadObject, "", "  ")
		if err != nil {
			return "", "", fmt.Errorf("failed to marshal payload object: %v", err)
		}
		return solveResp.URL, string(payloadBytes), nil
	}

	// Return the "url" and "payload" field
	return solveResp.URL, payloadString, nil
}

PreviousBypass SolutionNextCommon Errors & Troubleshooting

Last updated 8 months ago

Was this helpful?