Author: bettr package authors
Date: 2026-05-18

# Server Mode Guide for bettr

bettr package authors

#### 2026-05-18

Version 1.6.0 and later

## 0.1 Overview

Version 1.6.0 introduces server mode, a new way to deploy and use bettr that enables browser-based JSON file uploads, automatic caching, and programmatic data loading via URLs. This makes bettr suitable for:

- Multi-user server deployments where different users need to visualize their own data
- Web-based workflows without requiring R programming knowledge
- Data sharing through portable JSON files and direct links

## 0.2 What’s New in Version 1.6.0

### 0.2.1 Server Mode for JSON Uploads

The `bettr()` function now supports a `serverMode` parameter that launches the app in a special mode where users upload JSON files through the browser.

Benefits:

- No R programming required for end users
- Multiple users can use the same server instance with their own data
- Data is isolated per user session
- Automatic browser caching for quick reload

### 0.2.2 JSON Serialization

New functions for converting bettr data to/from JSON format:

- `bettrToJSON()` - Export `SummarizedExperiment` to JSON
- `bettrFromJSON()` - Import JSON back to `SummarizedExperiment`

Benefits:

- Portable data format (language-agnostic)
- Easy data sharing between users and systems
- Preserves all metadata, colors, weights, and transformations
- Enables web-based workflows

### 0.2.3 Browser localStorage Caching

Automatic client-side caching of uploaded JSON data in server mode.

What gets cached:

- Uploaded JSON data

Benefits:

- Page refresh doesn’t lose your work
- Survives browser restarts
- No manual saving required
- Automatic caching after upload

### 0.2.4 Cache Versioning

Administrators can force cache invalidation when deploying updates.

Use cases:

- Deploy schema changes that require fresh data
- Force all users to re-upload after breaking changes
- Manage cache in multi-tenant environments
- Troubleshooting cache-related issues

### 0.2.5 URL Parameters for Programmatic Loading

Load JSON data automatically via URL query parameters.

Benefits:

- Create direct links to specific visualizations
- Integrate with external tools and pipelines
- Automate opening visualizations after benchmark runs
- Share analysis results with a simple URL

## 0.3 Server Mode Basics

### 0.3.1 Starting a Server

    library(bettr)

    # Basic server mode
    bettr(serverMode = TRUE)

    # With cache versioning
    bettr(serverMode = TRUE, cacheVersion = "v1.0")

    # Custom theme
    bettr(serverMode = TRUE, bstheme = "flatly")

### 0.3.2 What Happens When You Start Server Mode

1. The app starts listening on a local port (e.g., `http://127.0.0.1:4567`)
2. Users navigate to this URL in their browser
3. The upload interface is displayed
4. Users can:
   - Upload JSON files manually
   - Have data loaded automatically via URL parameters (if provided)
5. Once data is uploaded, the full bettr interface appears
6. All interactions are automatically cached in the browser

### 0.3.3 User Interface

Upload Mode Interface:

- Clean, simple upload area
- “Choose JSON File” button
- Information about browser caching
- No “Close app” button (for multi-user safety)

After Upload:

- Full bettr visualization interface
- All standard features available
- “Load Data” panel for uploading new files
- “Clear Cached Data” button

## 0.4 JSON Serialization

### 0.4.1 Creating JSON Files

#### 0.4.1.1 From Data Frames

    library(bettr)

    # Create benchmark data
    benchmark_data <- data.frame(
        Method = c("AlgorithmA", "AlgorithmB", "AlgorithmC"),
        Accuracy = c(0.95, 0.92, 0.89),
        Speed = c(120, 150, 100),
        Memory = c(256, 512, 128)
    )

    # Add metric metadata
    metric_info <- data.frame(
        Metric = c("Accuracy", "Speed", "Memory"),
        Type = c("Quality", "Performance", "Resource"),
        Unit = c("Proportion", "ms", "MB")
    )

    # Define initial transformations
    transforms <- list(
        Speed = list(flip = TRUE, transform = "[0,1]"),
        Memory = list(flip = TRUE, transform = "[0,1]")
    )

    # Create SummarizedExperiment
    bettrSE <- assembleSE(
        df = benchmark_data,
        idCol = "Method",
        metricInfo = metric_info,
        initialTransforms = transforms
    )

    # Export to JSON
    json_file <- tempfile(fileext = ".json")
    bettrToJSON(bettrSE, file = json_file)

Click to view example JSON structure

The exported JSON file has the following structure:

    {
      "idCol": "Method",
      "data": [
        {
          "Method": "AlgorithmA",
          "Accuracy": 0.95,
          "Speed": 120,
          "Memory": 256,
          "_row": "AlgorithmA"
        },
        {
          "Method": "AlgorithmB",
          "Accuracy": 0.92,
          "Speed": 150,
          "Memory": 512,
          "_row": "AlgorithmB"
        },
        {
          "Method": "AlgorithmC",
          "Accuracy": 0.89,
          "Speed": 100,
          "Memory": 128,
          "_row": "AlgorithmC"
        }
      ],
      "metricInfo": [
        {
          "Metric": "Accuracy",
          "Type": "Quality",
          "Unit": "Proportion"
        },
        {
          "Metric": "Speed",
          "Type": "Performance",
          "Unit": "ms"
        },
        {
          "Metric": "Memory",
          "Type": "Resource",
          "Unit": "MB"
        }
      ],
      "idInfo": {},
      "initialWeights": {},
      "initialTransforms": {
        "Speed": {
          "flip": true,
          "transform": "[0,1]"
        },
        "Memory": {
          "flip": true,
          "transform": "[0,1]"
        }
      }
    }

Key components:

- `idCol`: Name of the identifier column
- `data`: Array of objects, one per method with all metric values
- `metricInfo`: Metadata about each metric (optional classifications, units, etc.)
- `idInfo`: Additional metadata about methods (optional)
- `initialWeights`: Default metric weights (optional)
- `initialTransforms`: Transformations to apply to metrics (flip for “lower is better”, transform for normalization)

#### 0.4.1.2 From Existing SummarizedExperiment

    # If you already have a SummarizedExperiment
    json_file <- tempfile(fileext = ".json")
    bettrToJSON(my_existing_SE, file = json_file)

    # Get JSON as string (for programmatic use)
    json_string <- bettrToJSON(my_existing_SE, file = NULL)

### 0.4.2 Reading JSON Files

    # Read from file
    bettrSE <- bettrFromJSON(file = "benchmark_results.json")

    # Read from JSON string
    bettrSE <- bettrFromJSON(json = json_string)

    # Use in non-server mode
    bettr(bettrSE = bettrSE)

## 0.5 URL Parameters for Programmatic Loading

### 0.5.1 Overview

URL query parameters allow you to automatically load JSON data when users open the app.

### 0.5.2 Two Loading Methods

#### 0.5.2.1 Load from URL (`jsonUrl`)

    http://localhost:4567/?jsonUrl=https://example.com/data.json

Use cases:

- Data hosted on web servers
- GitHub raw file URLs
- Cloud storage (S3, Google Cloud Storage, etc.)
- Internal company servers

Example:

    # Start server
    bettr(serverMode = TRUE)

    # Construct URL
    base_url <- "http://localhost:4567"
    data_url <- "https://raw.githubusercontent.com/user/repo/main/results.json"
    full_url <- paste0(base_url, "/?jsonUrl=", URLencode(data_url, reserved = TRUE))

    # Open in browser
    browseURL(full_url)

#### 0.5.2.2 Load from File Path (`jsonFile`)

    http://localhost:4567/?jsonFile=/absolute/path/to/data.json

Use cases:

- Local server deployments
- Internal network file shares
- Automated pipelines on same machine
- Development and testing

Example:

    # Start server
    bettr(serverMode = TRUE)

    # Construct URL
    base_url <- "http://localhost:4567"
    file_path <- "/Users/username/benchmarks/latest_results.json"
    full_url <- paste0(base_url, "/?jsonFile=", URLencode(file_path, reserved = TRUE))

    # Open in browser
    browseURL(full_url)

Using the included example data:

The bettr package includes a pre-exported JSON file from the DuoClustering2018 dataset that can be used for testing and examples.

    # Start server
    bettr(serverMode = TRUE)

    # Get path to included example JSON file
    json_path <- system.file("extdata", "duo2018_bettr.json", package = "bettr")

    # Construct URL
    base_url <- "http://localhost:4567"
    full_url <- paste0(base_url, "/?jsonFile=", URLencode(json_path, reserved = TRUE))

    # Open in browser
    browseURL(full_url)

## 0.6 Browser Cache Management

### 0.6.1 How Caching Works

1. Automatic Save:
   - When you upload a JSON file, it’s saved to browser localStorage
   - Happens immediately after successful upload
   - No manual action required
2. Automatic Restore:
   - When you reload the page, cached data is automatically restored
   - A notification confirms the restoration
3. Cache Storage:
   - Stored in browser’s localStorage (typically 5-10MB limit)
   - Specific to your browser and domain
   - Persists across browser restarts
   - Not shared across different browsers or devices

### 0.6.2 Manual Cache Control

#### 0.6.2.1 Clear Cache Button

Located in the “Load Data” accordion panel:

    Load Data
    ├── Choose JSON File
    └── Clear Cached Data (button)

Click to:

- Remove all cached data
- Start fresh with a new dataset
- Free up browser storage

### 0.6.3 Cache Versioning (Administrators)

#### 0.6.3.1 Setting Up Versioning

    # Deploy version 1.0
    bettr(serverMode = TRUE, cacheVersion = "v1.0")

    # Later, deploy version 1.1 with breaking changes
    bettr(serverMode = TRUE, cacheVersion = "v1.1")

#### 0.6.3.2 Version String Format

Any string works - choose what makes sense for your workflow:

    # Semantic versioning
    cacheVersion = "v1.2.3"

    # Date-based
    cacheVersion = "2025-10-07"

    # Build numbers
    cacheVersion = "build-456"

    # Custom
    cacheVersion = "production-release-oct2025"

#### 0.6.3.3 User Experience

When version changes:

1. User opens the app
2. Browser detects version mismatch
3. Cache is automatically cleared
4. User sees: “Cache was cleared due to version update. Please upload your data.”
5. User uploads their JSON file again
6. New cache is created with current version

# Session info

    sessionInfo()
    #> R version 4.6.0 Patched (2026-05-01 r89994)
    #> Platform: aarch64-apple-darwin23
    #> Running under: macOS Tahoe 26.3.1
    #>
    #> Matrix products: default
    #> BLAS:   /Library/Frameworks/R.framework/Versions/4.6/Resources/lib/libRblas.0.dylib
    #> LAPACK: /Library/Frameworks/R.framework/Versions/4.6/Resources/lib/libRlapack.dylib;  LAPACK version 3.12.1
    #>
    #> locale:
    #> [1] C/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8
    #>
    #> time zone: America/New_York
    #> tzcode source: internal
    #>
    #> attached base packages:
    #> [1] stats4    stats     graphics  grDevices utils     datasets  methods
    #> [8] base
    #>
    #> other attached packages:
    #>  [1] dplyr_1.2.1                 tibble_3.3.1
    #>  [3] SummarizedExperiment_1.43.0 Biobase_2.73.1
    #>  [5] GenomicRanges_1.65.0        Seqinfo_1.3.0
    #>  [7] IRanges_2.47.1              S4Vectors_0.51.2
    #>  [9] BiocGenerics_0.59.2         generics_0.1.4
    #> [11] MatrixGenerics_1.25.0       matrixStats_1.5.0
    #> [13] bettr_1.9.0                 BiocStyle_2.41.0
    #>
    #> loaded via a namespace (and not attached):
    #>  [1] gridExtra_2.3         rlang_1.2.0           magrittr_2.0.5
    #>  [4] clue_0.3-68           GetoptLong_1.1.1      otel_0.2.0
    #>  [7] compiler_4.6.0        png_0.1-9             vctrs_0.7.3
    #> [10] stringr_1.6.0         pkgconfig_2.0.3       shape_1.4.6.1
    #> [13] crayon_1.5.3          fastmap_1.2.0         magick_2.9.1
    #> [16] backports_1.5.1       XVector_0.53.0        labeling_0.4.3
    #> [19] utf8_1.2.6            learnr_0.11.6         shinyjqui_0.4.1
    #> [22] promises_1.5.0        rmarkdown_2.31        tinytex_0.59
    #> [25] purrr_1.2.2           xfun_0.57             cachem_1.1.0
    #> [28] jsonlite_2.0.0        later_1.4.8           DelayedArray_0.39.2
    #> [31] parallel_4.6.0        cluster_2.1.8.2       R6_2.6.1
    #> [34] bslib_0.11.0          stringi_1.8.7         RColorBrewer_1.1-3
    #> [37] rpart_4.1.27          jquerylib_0.1.4       Rcpp_1.1.1-1.1
    #> [40] bookdown_0.46         assertthat_0.2.1      iterators_1.0.14
    #> [43] knitr_1.51            base64enc_0.1-6       httpuv_1.6.17
    #> [46] Matrix_1.7-5          nnet_7.3-20           tidyselect_1.2.1
    #> [49] rstudioapi_0.18.0     dichromat_2.0-0.1     abind_1.4-8
    #> [52] yaml_2.3.12           doParallel_1.0.17     codetools_0.2-20
    #> [55] lattice_0.22-9        shiny_1.13.0          withr_3.0.2
    #> [58] S7_0.2.2              evaluate_1.0.5        foreign_0.8-91
    #> [61] circlize_0.4.18       pillar_1.11.1         BiocManager_1.30.27
    #> [64] checkmate_2.3.4       DT_0.34.0             foreach_1.5.2
    #> [67] rprojroot_2.1.1       ggplot2_4.0.3         scales_1.4.0
    #> [70] xtable_1.8-8          glue_1.8.1            Hmisc_5.2-5
    #> [73] tools_4.6.0           data.table_1.18.4     Cairo_1.7-0
    #> [76] cowplot_1.2.0         grid_4.6.0            tidyr_1.3.2
    #> [79] sortable_0.6.0        colorspace_2.1-2      htmlTable_2.5.0
    #> [82] Formula_1.2-5         cli_3.6.6             S4Arrays_1.13.0
    #> [85] ComplexHeatmap_2.29.0 gtable_0.3.6          sass_0.4.10
    #> [88] digest_0.6.39         SparseArray_1.13.2    rjson_0.2.23
    #> [91] htmlwidgets_1.6.4     farver_2.1.2          htmltools_0.5.9
    #> [94] lifecycle_1.0.5       GlobalOptions_0.1.4   mime_0.13