The service that runs Recorded Login and Custom User Behavior recordings is called Trails. If you for some reason need to modify your .trail files containing your recordings, please refer to this documentation.

For most use cases, you will not need to refer to this documentation to troubleshoot or solve any issues you might experience while setting up your Recorded Login. For a general introduction and troubleshooting tips to this functionality, please refer to this article instead.

Background

Trails is a way for Detectify to reach different states of a web application. This can be anything from authenticating (logging in), to adding an item to an e-commerce shopping cart. The entire service is based around a JSON specification containing various actions. An action could be, "move the mouse cursor", "click on an element" or "enter some text in an input/textarea".

By performing these events, various requests will be made. These requests are recorded for future use. Any cookie being set will be used elsewhere later when performing crawling and security testing.

Description

The data format is a JSON document containing two arrays of actions. The actions define how we are to interact with the site. The first set of arrays is called the "Commands"-node. Everything defined therein will run the first time the trail is executed. The second node is called "SanityChecks". Like with "Commands", this node contain a set of actions. The difference is that "SanityChecks" will run after all "Commands" are done (and Detectify have reached the assumed state), and then once more per minute indefinitely. The reason for this behavior is to validate that we are still authenticated or otherwise have reached the correct state in the application. If any assertion fail, then we assume the state is lost from "Commands", and the entire process will restart and "Commands" will run again in an attempt to regain the state.

The entire document should be considered a checklist. On the first execution all action nodes stored in "Commands" will be executed. A failure to execute an action (or if an assertion fails) will terminate the chain of commands and the trail should be considered failed. If all "Commands" execute successfully the trail is working. When the trail reaches a working state the "SanityChecks" will run sequentially in a similar manner as of "Commands". If the "SanityChecks" fail (either by a failed action or by assertion), the entire chain of "Commands" will have to re-run to reach the same initial state again. The "SanityChecks" should run in a loop to constantly verify that the correct states are reached.
 
Example file

Note: There are JavaScript comments in this file, so it may or may not be serializable to proper JSON.
 
{
    "Type": "Trail",
    "Version": "4.0",
    "CreationDate": "2019-08-08",
    "Name": "example.com-login",

    // Run this to reach a given state (i.e, authenticate as a user)
    "Commands": [{
            "Type": "Selenium",
            "Version": "1.0",
            "Command": "open",
            "Target": "https://example.com/login",
            "Value": ""
        }, {
            "Type": "Selenium",
            "Version": "1.0",
            "Command": "Type",
            "Target": "input=username",
            "Value": "admin"
        }, {
            "Type": "Selenium",
            "Version": "1.0",
            "Command": "Type",
            "Target": "input=password",
            "Value": "secret"
        }, {
            "Type": "Selenium",
            "Version": "1.0",
            "Command": "click",
            "Target": "input=Login",
            "Value": ""
        }, {
            "Type": "Selenium",
            "Version": "1.0",
            "Command": "assertTitle",
            "Target": "Welcome admin!",
            "Value": ""
        }
    ],

    // Will run sequentially in a loop once per minute, if the assertion fails re-run "Commands"
    "SanityChecks": [
        {
            "Type": "Selenium",
            "Version": "1.0",
            "Command": "open",
            "Target": "http://example.com/profile",
            "Value": ""
        }, {
            "Type": "Selenium",
            "Version": "1.0",
            "Command": "assertTitle",
            "Target": "Welcome admin!",
            "Value": ""
        }
    ]
}

Actions

Here is the list of supported actions.

Selenium actions:

TypeVersionCommandTargetValueDescription
Selenium1.0clickElementN/APerforms a click operation.
Selenium1.0clickAndWaitElementN/APerforms a click operation and waits for a new page to load.
Selenium1.0openURLN/AOpens a page using a URL.
Selenium1.0typeElementTextEnters text in an input.
Selenium1.0verifyElementPresent/assertElementPresentElementN/AUse this command when you must test for the presence of a specific UI element, rather than its content. This verification does not check the text, only the HTML tag. One common use is to check for the presence of an image.
Selenium1.0verifyText/assertTextElementTextUse verifyText when both the text and its UI element must be tested. verifyText must use a locator. If you choose an XPath or DOM locator, you can verify that specific text appears at a specific location on the page relative to other UI components on the page.
Selenium1.0verifyTextPresent/assertTextPresentTextN/AThe command verifyTextPresent is used to verify specific text exists somewhere on the page. It takes a single argument–the text pattern to be verified.
Selenium1.0verifyTitle/assertTitleTextN/AVerifies an expected page title.
Selenium1.0verifyURL/assertURLTextN/AVerifies an expected page URL.
Selenium1.0waitForElementPresentElementN/APauses execution until an expected UI element, as defined by its HTML tag, is present on the page.
Selenium1.0waitForPageToLoadIntegerN/APauses execution until an expected new page loads. Called automatically when clickAndWait is used. The target is a timeout in milliseconds.

Detectify defined UserActions:


TypeVersionCommandTargetValueArgumentsDescription
UserAction1.0blurElementElementN/AUser loses focus on element / input. If we fail to find the Element in Target, use the Element in Value.
UserAction1.0focusElementElementN/AUser gains focus on element / input. If we fail to find the Element in Target, use the Element in Value.
UserAction1.0inputElementElementN/AThis more or less will do element.value = x. After updating the element value we will dispatch "change"-event. If we fail to find the Element in Target, use the Element in Value.
UserAction1.0keyDownElementElementkeyCode, key, code, [text]User pressed a sigle key. Simulates a key-down event with the Target Element in focus. On failure tries the Element specified in Value.
UserAction1.0keyPressElementElementkeyCode, key, code, [text]Simulates a keystroke with the Target Element in focus. On failure tries the Element specified in Value. The only practical difference between KeyDown and KeyPress is that KeyPress relays the character resulting from a keypress, and is only called if there is one.
UserAction1.0keyUpElementElementkeyCode, key, code, [text]User stopped pressing single key. Simulates a key-up event with the Target Element in focus. On failure tries the Element specified in Value.
UserAction1.0mouseClickElementElementN/AClicks on an element (similar to Selenium 1.0 click). The Target will be the element we wish to click on. If this fails we will click on the element specified in Value.
UserAction1.0mouseDownElementElementN/APushes down the mouse on the Element specified in Target. If no element could be found in Target, use the Element specified in Value.
UserAction1.0mouseUpElementElementN/AReleases the mouse button on the Element specified in Target. If no element could be found in Target, use the Element specified in Value.
UserAction1.0typeElementTextElementEnters text in an input. This command is very similar to Selenium.type but adds support for multiple elements
UserAction1.0reload/refreshN/AN/AN/ATrigger a refresh of the page.
UserAction1.0reloadNoCache/refreshNoCacheN/AN/AN/ATrigger a hard refresh of the page (disregarding any cached content).
UserAction1.0scrollIntegerIntegerN/ATrigger a scroll event. The Target-property is the X coordinate, the Value-property is the Y-coordinate. All UserActions will issue a scroll call first, before the actual action is executed. To try this in Chrome, run: window.scrollTo(100, 500);
UserAction1.0setViewport/setSizeIntegerIntegerN/AChanges the size of the viewport. The Target-attribute is the width. The Value-attribute is the height.
UserAction1.0waitForElementPresentElementIntegerN/APauses execution until an expected UI element, as defined by its HTML tag, is present on the page. Times out after the given value is reached.
UserAction1.0tabFocusTextN/AN/AThe Target-attributes defines which tab to focus on. The very first tab will have the ID "A". Any new tab or window will be called "B", "C", etc... If any tab (such as tab "B") is closed, Detectify will be unable to access tab B and the action will fail. The sequence of ID's will contiune indefinitely and no ID's will be reused.
UserAction1.0verifyTabCount/assertTabCountIntegerN/AN/AValidates that the amount of tabs/windows open correspond to the expected value

Detectify defined Helper actions:

TypeVersionCommandTargetValueDescription
Helper1.0sleepIntegerN/ASleeps for the Target-amount milliseconds.

Detectify specified Extractors:

TypeVersionCommandTargetValueDescription
Extractor1.0cookieTextN/AExtracts the specified cookie to use in other services.
Extractor1.0cookiesN/AN/AExtracts all observed cookies for all origins to use in other services (i.e, Crawler and Scanner).
Extractor1.0requestHeaderIntegerN/AExtracts the specified request header. This header will then be set in all future requests issued by other services (i.e, Crawler and Scanner).
Extractor1.0linksElementN/AExtracts all links under the specified element. If no element is specified, all links on the page will be extracted.
Extractor1.0screenshotN/AN/ATakes a screenshot.
Extractor1.0urlN/AN/AExtracts the current URL we're visiting. The next time we run the same trail, we will start from the extracted URL (however a Selenium open command will navigate away again).

Polyfill actions:

Note: These will polyfill the specified function group at the point where the command is executed. This means that page navigation might invalidate earlier polyfills. Can only be added manually to the trail and will never be set via the Chrome plugin.
TypeVersionCommandTargetValueDescription
Polyfill1.0credentialsN/AN/APolyfills navigator.credentials.store and navigator.credentials.get
 

Targets

TargetDescription
URL   Can be a relative or absolute URL.
Element   Any kind of selector to specify an element to focus on. Here is more information on what a selector is.
Text   A snippet of text to search for or to fill in. If the Text is used as a Target it will support globbing.
Integer   A positive number.


The "AndWait" commands

The difference between a command and its AndWait alternative is that the regular command (e.g. click) will do the action and continue with the following command as fast as it can, while the AndWait alternative (e.g. clickAndWait) tells the interpreter to wait for the page to load after the action has been executed.
The AndWait alternative is always used when the action causes the browser to navigate to another page or reload the present one.
Be aware, if you use an AndWait command for an action that does not trigger a navigation/refresh, your test will fail. This happens because the interpreter will reach the AndWait’s timeout without seeing any navigation (or page refresh) being made, causing the interpreter to raise a timeout exception.
See the specification for more information.


Locating elements

For many Selenium commands, a target is required. This target identifies an element in the content of the web application, and consists of the location strategy followed by the location in the format locatorType=location.
See the specification for more information.