Test using PFX certificates
You can upload and install .pfx (Personal Information Exchange) certificates on BrowserStack Automate to test websites and workflows that require client-certificate authentication.
To start testing with .pfx certificates, contact BrowserStack Support to have your certificates reviewed and validated.
Use cases
Testing with .pfx certificates is useful in scenarios such as:
- Testing websites that require a valid client certificate for authentication.
- Verifying workflows that depend on certificate-based access.
- Conducting compatibility checks for advisory portals that require authentication.
- Ensuring that certificate installation works across different operating systems and browsers.
Supported operating systems and browsers
The following operating systems and browsers support .pfx certificates:
| Operating System | Versions | Browsers |
|---|---|---|
| Windows | Windows 11 | Chrome |
| macOS | Sequoia, Tahoe | Chrome |
Upload your file to BrowserStack
Run the following upload media cURL command to upload your file to BrowserStack servers:
Here is a sample cURL response. It returns the media_url parameter value.
Set the capability in test script
To use certificate based authentication, set the customCertificates capability. Here is an example to set this capability in your config file:
package org.example.threads;
import com.fasterxml.jackson.core.JsonProcessingException;
import org.openqa.selenium.*;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.remote.RemoteWebDriver;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import com.fasterxml.jackson.databind.ObjectMapper;
public class BrowserStackClientCertTest {
public static final String USERNAME = "YOUR_USERNAME";
public static final String ACCESS_KEY = "YOUR_ACCESS_KEY";
public static final String URL = "https://" + USERNAME + ":" + ACCESS_KEY + "@hub-cloud.browserstack.com/wd/hub";
public static void main(String[] args) throws MalformedURLException, InterruptedException, JsonProcessingException {
MutableCapabilities capabilities = new MutableCapabilities();
ObjectMapper mapper = new ObjectMapper();
// ChromeOptions
ChromeOptions options = new ChromeOptions();
// SSL client certificate preference
Map<String, Object> certPref = new HashMap<>();
certPref.put("pattern", "https://client.badssl.com");
certPref.put("filter", Map.of("SUBJECT", Map.of("CN", "BadSSL Client Certificate")));
String certJsonString = mapper.writeValueAsString(certPref);
options.setExperimentalOption("prefs", Map.of(
"profile.managed_auto_select_certificate_for_urls", new String[]{certJsonString}
));
capabilities.setCapability(ChromeOptions.CAPABILITY, options);
// BrowserStack options
capabilities.setCapability("browserName", "Chrome");
capabilities.setCapability("browserVersion", "latest");
Map<String, Object> bstackOptions = new HashMap<>();
bstackOptions.put("os", "OS X");
bstackOptions.put("osVersion", "Sequoia");
bstackOptions.put("userName", "");
bstackOptions.put("accessKey", "");
bstackOptions.put("uploadMedia", new String[]{"media://xyz"});
bstackOptions.put("customCertificate", Map.of(
"media://xyz", Map.of("password", "badssl.com")
));
capabilities.setCapability("bstack:options", bstackOptions);
WebDriver driver = new RemoteWebDriver(new URL("https://USERNAME:ACCESS_KEY@hub-cloud.browserstack.com/wd/hub"), capabilities);
driver.get("https://client.badssl.com/");
Thread.sleep(2000);
System.out.println("Title: " + driver.getTitle());
driver.quit();
}
}
const { Builder, By, until } = require('selenium-webdriver');
const { Capabilities } = require('selenium-webdriver');
const fs = require('fs');
const { debug } = require('console');
(async function runSelenium() {
const username = ""
const accessKey = ""
const capabilities = {
browserName: "Chrome",
browserVersion: "latest",
'bstack:options': {
os: "OS X",
osVersion: "Sequoia",
userName: "",
accessKey: "",
projectName: "test-cert",
buildName: "pfx cert check",
sessionName: "session performance test3",
accessibility: true,
selfHeal: true,
"chromeOptions": {
"prefs": {
"profile.managed_auto_select_certificate_for_urls": [
JSON.stringify({
"pattern": "https://client.badssl.com", // this is a public website
"filter": {
"SUBJECT": { "CN": "BadSSL Client Certificate" }
}
})
]
}
},
debug: true,
uploadMedia : ['media://xyz'],
customCertificate: {
"media://xyz" : {
"password": "xyz",
}
}
}
};
let driver;
try {
driver = await new Builder()
.usingServer(`https://${username}:${accessKey}@hub-cloud.browserstack.com/wd/hub`)
.withCapabilities(capabilities)
.build();
console.log("connected done")
await driver.get("https://client.badssl.com/");
await driver.sleep(2000);
console.log("Taking screenshot...");
// 1. Take the screenshot
const image = await driver.takeScreenshot();
// 2. Save the Base64 string as a PNG file
fs.writeFileSync("screenshotpfx.png", image, "base64");
console.log("Screenshot saved to screenshot.png");
console.log("login done")
} catch (err) {
console.error("Test failed:", err.message);
} finally {
if (driver) {
await driver.quit();
}
}
})();
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;
using OpenQA.Selenium.Remote;
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
public class BrowserStackClientCertTest
{
public static readonly string USERNAME = "";
public static readonly string ACCESS_KEY = "";
public static readonly string HUB_URL = $"https://{USERNAME}:{ACCESS_KEY}@hub-cloud.browserstack.com/wd/hub";
public static void Main(string[] args)
{
IWebDriver driver = null;
try
{
ChromeOptions options = new ChromeOptions();
options.AddUserProfilePreference(
"profile.managed_auto_select_certificate_for_urls",
new[] {
"{\"pattern\":\"https://client.badssl.com\",\"filter\":{\"SUBJECT\":{\"CN\":\"BadSSL Client Certificate\"}}}"
}
);
// 🔹 Standard WebDriver caps
options.BrowserVersion = "latest";
// 🔹 BrowserStack options
Dictionary<string, object> bstackOptions = new Dictionary<string, object>
{
["os"] = "OS X",
["osVersion"] = "Sequoia",
["userName"] = USERNAME,
["accessKey"] = ACCESS_KEY,
["projectName"] = "test-cert",
["buildName"] = "pfx cert check",
["sessionName"] = "csharp certificate test",
["debug"] = true,
["selfHeal"] = true,
["uploadMedia"] = new string[] {
"media://xyz"
}
};
// 🔹 Client certificate auto-select prefs
Dictionary<string, object> certPref = new Dictionary<string, object>
{
["pattern"] = "https://client.badssl.com",
["filter"] = new Dictionary<string, object>
{
["SUBJECT"] = new Dictionary<string, string>
{
["CN"] = "BadSSL Client Certificate"
}
}
};
Dictionary<string, object> prefs = new Dictionary<string, object>
{
["profile.managed_auto_select_certificate_for_urls"] = new List<object> { certPref }
};
Dictionary<string, object> chromeOptions = new Dictionary<string, object>
{
["prefs"] = prefs
};
bstackOptions["customCertificate"] = new Dictionary<string, object>
{
["media://xyz"] =
new Dictionary<string, string>
{
["password"] = "badssl.com"
}
};
// Attach bstack:options → options
options.AddAdditionalOption("bstack:options", bstackOptions);
Console.WriteLine("Connecting to BrowserStack...");
driver = new RemoteWebDriver(new Uri(HUB_URL), options);
Console.WriteLine("Connected successfully!");
driver.Navigate().GoToUrl("https://client.badssl.com/");
Thread.Sleep(3000);
Console.WriteLine("Screenshot saved: " +
Path.GetFullPath("screenshotpfx.png"));
}
catch (Exception e)
{
Console.WriteLine("Test failed: " + e.Message);
}
finally
{
driver?.Quit();
}
}
}
import os
import time
import json
from selenium import webdriver
USERNAME = ""
ACCESS_KEY = ""
HUB_URL = f"https://{USERNAME}:{ACCESS_KEY}@hub-cloud.browserstack.com/wd/hub"
def run_selenium_test():
options = webdriver.ChromeOptions()
bstack_options = {
"os": "OS X",
"osVersion": "Sequoia",
"projectName": "test-cert",
"buildName": "pfx cert check",
"sessionName": "python cert test",
"userName": USERNAME,
"accessKey": ACCESS_KEY,
"uploadMedia": ["media://xyz"],
"customCertificate": {
"media://xyz": {
"password": "badssl.com"
}
},
"chromeOptions" : {
"prefs" : {"profile.managed_auto_select_certificate_for_urls":
[
json.dumps({
"pattern": "https://client.badssl.com",
"filter": {"SUBJECT": {"CN": "BadSSL Client Certificate"}}
})
]}
}
}
# Add BrowserStack caps to options
options.set_capability("bstack:options", bstack_options)
print("Connecting to BrowserStack...")
driver = webdriver.Remote(
command_executor=HUB_URL,
options=options
)
print("Connected successfully!")
driver.get("https://client.badssl.com/")
time.sleep(3)
driver.save_screenshot("screenshotpfx.png")
print("Screenshot saved!")
driver.quit()
if __name__ == "__main__":
run_selenium_test()
<?php
require_once('vendor/autoload.php');
use Facebook\WebDriver\Remote\RemoteWebDriver;
use Facebook\WebDriver\Remote\DesiredCapabilities;
use Facebook\WebDriver\WebDriverException;
class BrowserStackClientCertTest
{
private const USERNAME = "";
private const ACCESS_KEY = "";
// NOTE: HUB_URL is defined WITHOUT credentials here
private const HUB_URL = "https://hub-cloud.browserstack.com/wd/hub";
public static function runTest()
{
$driver = null;
try {
// 1. Base capabilities
$capabilities = DesiredCapabilities::chrome();
$capabilities->setCapability('browserVersion', '126.0'); // Use stable version
// 2. bstack:options (MUST include 'user' and 'key' explicitly for Hub processing)
$bstackOptions = [
'os' => 'OS X',
'osVersion' => 'Sequoia',
'userName' => self::USERNAME,
'accessKey' => self::ACCESS_KEY,
// Optional metadata
'projectName' => 'test-cert',
'buildName' => 'pfx cert check',
'sessionName' => 'csharp certificate test',
'accessibility' => true,
'selfHeal' => true,
'debug' => true,
// --- Certificate and Media Configuration ---
'uploadMedia' => ['media://xyz'],
'customCertificate' => [
'media://xyz' => [
'password' => 'badssl.com'
]
],
"chromeOptions" => [
'prefs' => [
"profile.managed_auto_select_certificate_for_urls" => [
json_encode([
"pattern" => "https://client.badssl.com",
"filter" => [
"SUBJECT" => [ "CN" => "BadSSL Client Certificate" ]
]
])
]
]
]
];
// 4. Attach capabilities
$capabilities->setCapability('bstack:options', $bstackOptions);
echo "Connecting to BrowserStack...\n";
// 5. Build driver using clean HUB URL and rely on BStack capabilities for auth
$driver = RemoteWebDriver::create(self::HUB_URL, $capabilities, 300000, 300000);
echo "Connected successfully. Session ID: " . $driver->getSessionID() . PHP_EOL;
// 6. Run test
$driver->get('https://client.badssl.com/');
// simple sleep to let browser load and (hopefully) auto-select certificate
sleep(5);
// Take screenshot
$imagePath = 'screenshotpfx.png';
$driver->takeScreenshot($imagePath);
echo "Screenshot saved to {$imagePath}\n";
} catch (WebDriverException $e) {
error_log("WebDriverException: " . $e->getMessage());
echo "WebDriverException: " . $e->getMessage() . PHP_EOL;
} catch (\Exception $e) {
error_log("Exception: " . $e->getMessage());
echo "Exception: " . $e->getMessage() . PHP_EOL;
} finally {
if ($driver !== null) {
$driver->quit();
}
}
}
}
BrowserStackClientCertTest::runTest();
require 'rubygems'
require 'selenium-webdriver'
# SET CHROME OPTIONS
LITERAL_CERTIFICATE_PREFERENCE_STRING = '{"pattern":"https://client.badssl.com","filter":{"SUBJECT":{"CN":"BadSSL Client Certificate"}}}'
caps = Selenium::WebDriver::Remote::Capabilities.chrome("chromeOptions" => {"prefs" => {'profile.managed_auto_select_certificate_for_urls' => [LITERAL_CERTIFICATE_PREFERENCE_STRING]} })
# SET CAPABILITY
caps['browser'] = 'Chrome'
caps['browser_version'] = '130.0'
caps['os'] = 'Windows'
caps['os_version'] = '11'
caps["uploadMedia"] = [
"media://xyz"
]
caps["customCertificate"] = {
"media://xyz" => {
"password" => "badssl.com"
}
}
driver = Selenium::WebDriver.for(:remote,
:url => "http://#{USERNAME}:#{ACCESS_KEY}@hub-cloud.browserstack.com/wd/hub",
:desired_capabilities => caps)
driver.navigate.to "https://client.badssl.com/"
driver.quit
We're sorry to hear that. Please share your feedback so we can do better
Contact our Support team for immediate help while we work on improving our docs.
We're continuously improving our docs. We'd love to know what you liked
We're sorry to hear that. Please share your feedback so we can do better
Contact our Support team for immediate help while we work on improving our docs.
We're continuously improving our docs. We'd love to know what you liked
Thank you for your valuable feedback!