Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 12 additions & 8 deletions .github/workflows/nightly-documentation-update.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,15 @@ jobs:
NightlyDocumentationUpdate-v4_5:
needs: NightlyDocumentationUpdate
if: ${{ !cancelled() }}
uses: 51Degrees/common-ci/.github/workflows/nightly-documentation-update.yml@main
with:
repo-name: ${{ github.event.repository.name }}
org-name: ${{ github.event.repository.owner.login }}
branch: version/4.5
dryrun: ${{ inputs.dryrun || false }}
secrets:
token: ${{ secrets.ACCESS_TOKEN }}
runs-on: ubuntu-latest
defaults:
run:
shell: pwsh
steps:
- uses: actions/checkout@v5
with:
token: ${{ secrets.ACCESS_TOKEN }}
ref: version/4.5
- env:
GITHUB_TOKEN: ${{ secrets.ACCESS_TOKEN }}
run: ./ci/generate-documentation.ps1 -Version '4.5'
6 changes: 3 additions & 3 deletions Documenting.md
Original file line number Diff line number Diff line change
Expand Up @@ -313,13 +313,13 @@ All terms should use the same format as the 51Degrees glossary, for capitals, hy
## Dependencies
### DoxyGen
We use a customised build of DoxyGen.
The source code is available from the [DoxyGen](https://51degrees.visualstudio.com/Documentation/_git/DoxyGen) repository. However, building from source can be [fiddly](https://www.doxygen.nl/manual/install.html).
Pre-built binaries can be downloaded from Sharepoint for [Linux](https://51degrees.sharepoint.com/:u:/r/Product%20Team/doxygen-linux.zip?csf=1&web=1&e=fTWXlN) or [Windows](https://51degrees.sharepoint.com/:u:/r/Product%20Team/doxygen-win.zip?csf=1&web=1&e=T7MvWo).
The source code is available from the [DoxyGen](https://github.com/51Degrees/doxygen) repository. However, building from source can be [fiddly](https://www.doxygen.nl/manual/install.html).
Pre-built binaries can be downloaded from Sharepoint for [Linux](https://51degrees.sharepoint.com/:u:/r/Product%20Team/doxygen-linux.zip?csf=1&web=1&e=fTWXlN) or [Windows](https://51degrees.sharepoint.com/:u:/r/Product%20Team/doxygen-win.zip?csf=1&web=1&e=T7MvWo). The Linux pre-buit binaries also live in the [Tools Repo](https://github.com/51Degrees/tools/tree/main/DoxyGen).

### GraphVis
In order for DoxyGen to generate nice diagrams, [GraphVis 2.38](https://graphviz.gitlab.io/_pages/Download/windows/graphviz-2.38.msi) must be installed.

### Pattern Lab
The css used in all documentation comes from the pattern lab submodule.

To generate the `main.min.css` needed by the documentation, follow the installation instructions in the [PatternLab readme](patternlab/README.md) to generat the css, then run ``gulp minify-css`` to minify it. The minified css will now live in `patternlab/source/css`.
To generate the `main.min.css` needed by the documentation, follow the installation instructions in the [PatternLab readme](patternlab/README.md) to generat the css, then run ``gulp minify-css`` to minify it. The minified css will now live in `patternlab/source/css`.
7 changes: 7 additions & 0 deletions docs/docs-main.min.css

Large diffs are not rendered by default.

115 changes: 115 additions & 0 deletions src/features/clientsideevidence.md
Original file line number Diff line number Diff line change
Expand Up @@ -160,3 +160,118 @@ For more detailed, language-specific steps, see the
examples such as the
[device detection examples](@ref Examples_DeviceDetection_GettingStarted_Web_Index)
or [reverse geocoding examples](@ref Examples_ReverseGeocoding_WebIntegration_Examples).

# Static and Quasi-Static Script Approaches

## Overview
51Degrees provides multiple ways to integrate device detection using client-side JavaScript evidence collection.
The default approach is a dynamic integration scenario, but semi-static and conceptual static methods can also be used depending on implementation constraints.

### Dynamic Scenario (Default)
In a dynamic integration scenario, the client-side evidence collection script is generated dynamically for each request.
This ensures that the JavaScript snippets used for detection are always specific to the client’s device or browser context.
A typical integration example:
```html
<script src="<51degrees.core.js URL>"></script>
```
The `src` attribute points to a 51Degrees client-side evidence endpoint that dynamically produces the `51degrees.core.js` script.
This script includes JavaScript snippets that perform client-side evidence collection.

## Process Overview

### Dynamic Generation
* The script is generated for every request based on initial evidence (e.g., User-Agent).
* JavaScript snippet properties are retrieved from the data file on the server.
* The final script differs depending on the detected client type.

### Snippet Retrieval and Integration
* JavaScript snippet properties are stored within the 51Degrees data file.
* The Device Detection Engine retrieves these as part of the detection results.
* Example:
* If supplied User-Agent corresponds to an iPhone, the `javascripthardwareprofile` property contains iPhone-specific code.
* If it indicates macOS, the property contains Mac-specific code.
* These snippets are updated daily with the data file.

### Script Assembly
* The `JSONBuilderElement` and `JavaScriptBuilderElement` (part of the 51Degrees @Pipeline) inject the snippet properties into a JavaScript template.
* Templates are available at: (https://github.com/51Degrees/javascript-templates).
* The result is the complete `51degrees.core.js` script.

### Client-Side Execution
* The `51degrees.core.js` script executes each snippet sequentially in the client browser.
* Snippets store collected evidence in the session storage (or cookies) using `51D_` prefixes, for example:
* `51D_profileIds`
* The collected evidence will be sent to the server as property overrides and also received in the client code in a callback provided to a `fod.complete` function:
```js
fod.complete(function() {
// Handle collected evidence here
});
```

### Profile Matching
* The collected `51D_profileIds` values must be matched against the same data file used to generate the snippets.
* This ensures accurate and consistent device identification.

## Semi-Static Scenario

If your environment already includes a static script (e.g., `<script src="<myscript.js URL>">`) and cannot add another dynamically generated one, a semi-static integration approach is recommended.
This method merges 51Degrees-generated snippets into your existing script, allowing some dynamic behaviour while maintaining a mostly static setup.

Please note the implementation of this approach is not part of the 51Degrees solution as it involves your custom system, thus you have to implement it yourself - we only give the general outline here.

### Implementation Options

### Option 1 — Dynamic Merge per Request
* Modify your existing script to be generated dynamically on your server.
* Pass all HTTP header evidence to the 51Degrees @Pipeline during script generation.
* The @Pipeline returns an appropriate version of the snippet (e.g., different for iPhone, iPad, or Mac).
* Your script includes that snippet dynamically before returning it to the client.

### Option 2 — Cached Variants (Semi-Static)
* Pre-generate and cache short-lived variants of the 51Degrees-generated script for device groups (e.g., iPhone, iPad, Mac).
* Your script can decide which cached snippet to load based on basic client-side conditions.
* Cached variants should be refreshed whenever the data file updates.
* Always ensure that `51D_profileIds` are matched against the same data file from which snippets were derived.

## Conceptual Static Approach

### Implementation Considerations
* **Extraction** - Extract relevant JavaScript snippets (for specific device groups such as iPhones) directly from the current 51Degrees data file.
* **Maintenance** - Refresh static scripts daily or as frequently as possible to remain synchronized with data file updates.
* **Customization** - Implementation details depend on your environment.
There is no one-size-fits-all static solution. Stale or outdated static scripts can lead to incorrect device identification.

### Comparison Summary
| Approach Type | Script Generation | Update Frequency | Typical Use Case |
| ------------- | ----------------- | ---------------- | ---------------- |
| Dynamic (Default) | Fully dynamic per request | Real-time | Standard 51Degrees integration for dynamic or modern sites |
| Semi-Static | Cached or merged dynamically | On data file update | When dynamic script loading is restricted |

### Best Practices

### Synchronization
* Always ensure that the client-side snippets and server-side data file originate from the same data file version. Mismatched versions can cause inaccurate device matching or inconsistent detection results.

### Data File Updates
* Refresh your data file and any cached or static snippets daily (or as frequently as your infrastructure allows).
* Automate the refresh process wherever possible to prevent stale results.

### Caching Strategy
* For semi-static scenarios, limit cache lifetime to no longer than the data file update cycle.
* If using a CDN, configure cache invalidation or revalidation logic based on the 51Degrees data update frequency.

### Version Control
* Keep a record of the data file version or timestamp used to generate each JavaScript snippet.
* This helps debug inconsistencies between collected evidence and device matching.

### Fallback Handling
* Implement fallback logic for cases where no `51D_profileIds` are available (e.g., script blocked, or execution failed).
* Fallback can use baseline server-side detection or cached evidence.

### Testing
* Test across major device types (mobile, tablet, desktop) to ensure snippets behave correctly in different environments.
* Validate that the evidence collection keys (e.g., `51D_profileIds`) are properly populated in storage and transmitted.

### Security
* Avoid exposing sensitive internal URLs or raw data file paths in the browser.
* Serve dynamically generated scripts through your own API gateway or proxy if needed.