# Launching browser

As described in How it works - Basics, to start the browser you should first locate chrome and chromedriver binaries as you are going to use them.

You can use them to start browser for both automation (requires chromedriver) or manual use. Regardless of how you launch it, there are four command-line arguments that you usually should provide to the browser.

# Command-line arguments

  1. --user-data-dir - the path to the profile folder. Will be used by the browser to read and store profile data such as Cookies, Passwords, History, Bookmarks etc.
  2. --profile-id - the ID of the profile
  3. --browser-key - the browserKey from the start profile response
  4. --profile-lock - the profileLock from the start profile response

All the parameters are completely optional - of course, if you do not want to use fingerprint 😅. Jokes aside - this might be useful for testing purposes, e.g. testing command-line arguments, debugging X11 display features or anything else that is not related to profile launch.

To enable fingerprint spoofing though - you must absolutely provide both --profile-id and --browser-key arguments.

The parameter --user-data-dir should point to the folder created by the download folder step, or any other folder you want to use instead. If not provided, the default Chromium profile will be used.

The parameter --profile-lock is surely recommended if you used lock mechanism, as the browser sends ping requests to the server indicating that your session is active. If you used lock when starting profile, but forgot to set it when launching the browser, the session lock will become inactive after 5 minutes, as no ping messages were received.

# Launching

If you develop some sort of client application and you just need to start the browser window without using Selenium, you should be using the same Process API as you would use for downloading folder with aemulari. You would set the command-line arguments directly to chrome binary.

But, we assume that the main reason you are reading this guide is that you actually want to automate things. So, as you could see in How it works - Basics, you would create a ChromeOptions object and provide it with the flags you want to start chrome with. Usually those four described above. Then you would initialize ChromeDriver object with these options and you are good to go.

When you start the browser, it does multiple things. First, it initializes your fingerprint. Then it sets up proxy. If you use SSH proxy, it also involves port forwarding, so you get a local SOCKS proxy forwarding to your server via SSH protocol. Lastly, if you use automatic WebRTC or Geolocation features, it fetches current parameters for these APIs.

Any of these operations might fail, and if it does, the browser process will exit with a corresponding error code and an error message printed to stdout.

If everything goes fine, the browser window will open and you will get a message Successfully started printed to stdout.

# Error codes

Code Meaning
1 Can indicate anything from invalid arguments to some network errors. There should be an error message printed to stdout
2 Network error (bad curl code somewhere). Usually this indicates that the proxy is invalid. There must be an error message printed to stdout
3 IP Change URL error. The endpoint responded with non-200 response code. There must be an error printed to stdout
4 IP Change URL error. Network error (bad curl code). There must be an error printed to stdout
6 Automatic field error. Unauthorized (401). Your browserKey must have expired
7 Automatic field error. Network error (bad curl code). There must be an error printed to stdout
8 Automatic field error. Server responded with non-200 response code. It will be printed to stdout
103 Forbidden. The profile ID and browser key combination not found
104 Not Found. The profile does not exist
110 Gone. The profile is deleted and is currently in Recycle Bin. You must restore it to use it
124 Failed Dependency. The proxy from the Proxy List assigned to this profile does not exist anymore. Update the profile with a new proxy
200 Internel Server Error. There will be no message printed to stdout
255 You might get this code if there is a problem with SSH proxy. The stdout might have an error message

You will get the server's error message printed to stdout in case you get error codes 103-122. Usually you should contact support if you get exit codes 1-8, 200 or 255 and have no way of fixing it yourself.

You will also get an error message of form CURL error: <message> printed to stdout in case of exit code 2, which might help you in fixing the error yourself. Though, if you are sure that your proxy is valid and you still keep getting this code, contact support so that we can investigate the issue.

# ChromeDriver behavior

If everything goes fine, you will get browser window opened and be able to control the browser as usual. But, if the browser launch fails, the process of getting an error is a bit trickier.

If you use Selenium, you will get a SessionNotCreatedException exception thrown on ChromeDriver initialization with a message that, apart from a lot of not really useful information, will contain a string of form Surfinite code: <exitcode>. Check the code example below.

# Code example

val profileId = "6335f488e21dc11848fd225e"
val useLock = false

// Start the profile
val startProfileResponse = startProfile(
    profileId = profileId,
    useLock = useLock
)

// Skip downloading folder, just set empty dir
val profileDir = File("profiledirs")
    .combineSafe(profileId)

val options = ChromeOptions()
options.addArguments(
    listOf(
        "--user-data-dir=${profileDir.absolutePath}",
        "--profile-id=$profileId",
        "--browser-key=${startProfileResponse.browserKey}"
    ).let { args ->
        // if there is a profileLock, add it to chrome arguments
        if (startProfileResponse.profileLock != null) {
            args + "--profile-lock=${startProfileResponse.profileLock}"
        } else {
            args
        }
    }
)

val chromePath = "/home/myuser/.surfinite/browser/chrome"
val chromeDriverPath = "/home/myuser/.surfinite/browser/chromedriver"

// Set Chrome binary path
options.setBinary(chromePath)
// Set Chromedriver binary path
System.setProperty("webdriver.chrome.driver", chromeDriverPath)

val driver = runCatching {
    ChromeDriver(options)
}.getOrElse {
    if (it is SessionNotCreatedException) {
        val message = it.message
        if (message != null && message.contains("Surfinite code")) {
            val surfiniteCode = message
                .substringAfter("Surfinite code: ")
                .substringBefore('\n')
            println("Got Surfinite error code: $surfiniteCode")
        } else {
            // Error not related to fingerprint or proxy
            it.printStackTrace()
        }
    } else {
        // Some other error
        it.printStackTrace()
    }
    return
}

driver["https://example.com"]

# Troubleshooting

Unfortunately, you won't get any output to stdout when using ChromeDriver. So, if you get errors 1-8 or 255, you will have no chance of fixing it yourself from the output. To try to debug what is going on and get chrome's output, you would have to start the browser without ChromeDriver, fix the error, and then return back to using ChromeDriver.

If you work with proxies or under some conditions that errors are frequent for you, and you want to see the output from stdout everytime you launch the browser, contact our support. We haven't seen such cases before and were not working on this. This is still possible, just not in our current roadmap.