# How to Create a UCSC Data Hub for Visualizing BAM, VCF, and BED Files

By the end of this guide you will have a working UCSC track hub at a public HTTPS address, with an alignment track built from a BAM file, a variant track built from a VCF file, and an interval track built from a BED or bigBed file. You will also know how to verify that the browser is reading the right bytes, how to diagnose the most common failure messages, and how to keep the hub fast as files grow.

You need a Linux or macOS shell, `samtools`, `bgzip` and `tabix` from htslib, the UCSC kent utilities (`fetchChromSizes`, `bedToBigBed`, `bigBedInfo`), and an HTTPS-capable web server such as nginx, Apache, or an object store with range-request support. You also need to know the exact UCSC assembly name for your reference, for example `hg38` for GRCh38 or `mm10` for GRCm38.

## What a UCSC Data Hub Is and What It Is Not

A UCSC data hub is a small set of plain-text configuration files that tells the [UCSC Genome Browser](/knowledge/bioinformatics/ucsc-genome-browser-beginner-tutorial-and-tips) where your data lives and how to render it. The browser does not copy, mirror, or store your BAM, VCF, or BED files. It reads the configuration, then requests only the byte ranges it needs from your web server as the user pans and zooms. That design is why a hub can serve multi-gigabyte alignment files without a database, and why you can update a track by replacing one data file while leaving the configuration untouched.

Three files form the minimum structure:

- `hub.txt` names the hub and points to the genome list.
- `genomes.txt` lists the assemblies and points to one trackDb file per assembly.
- `trackDb.txt` declares each track, its data URL, its type, and its display defaults.

The directory layout is usually one folder per assembly so that relative paths stay short and readable:

```
hub/
  hub.txt
  genomes.txt
  hg38/
    trackDb.txt
    sample.sorted.bam
    sample.sorted.bam.bai
    variants.vcf.gz
    variants.vcf.gz.tbi
    peaks.bigBed
```

A track hub is not a data repository, a backup system, or an access-control layer. It is a pointer plus rendering instructions. The moment the URL is public, the data behind it is public to anyone who knows or guesses the path. That distinction drives most of the operational advice later in this article.

The track hub format is one of several web-accessible routes for visualizing sequencing data, alongside standalone browsers and interactive plotting tools [1]. A browser such as JBrowse 2 takes a modular approach and loads a reference from FASTA plus annotation from GFF3 [2], while a track hub keeps the reference on UCSC's side and only streams your tracks. Both models work. The hub model is lighter to deploy when your organism is already hosted by UCSC, and it becomes more work when you need a custom assembly.

## The File Formats You Will Publish

Before you write a single configuration line, confirm what each file contains and what index it needs. Most hub failures are format failures in disguise.

### FASTA and FASTQ

FASTA is a text format for sequences. Each record starts with a `>` header line, followed by sequence lines. The reference genome that the browser displays is distributed internally as a indexed FASTA-like twoBit file, and FASTA is the standard input when you set up a browser against your own assembly [2]. FASTA carries no quality information.

FASTQ is a text format for raw reads. Each record has four lines: a `@` header, the sequence, a `+` separator, and a quality string encoded as Phred scores offset by 33. The quality string is the defining difference between FASTQ and FASTA. FASTA tells you which bases are present. FASTQ tells you which bases are present and how confident the sequencer was in each call.

Neither FASTQ nor FASTA is a genome browser track in the usual sense. You cannot drop a FASTQ file into a track hub and expect read alignments to appear. The visualization path is to align FASTQ reads against a FASTA reference, producing a coordinate-sorted BAM, and then publish that BAM. The distinction matters because new users often try to upload the raw read file and conclude that the hub is broken. Common formats for storing and coding genomic data, including the alignment and variant formats described below, are reviewed in the high-throughput sequencing literature [1].

### SAM, BAM, and CRAM

SAM is the text alignment format. BAM is its binary, BGZF-compressed equivalent. CRAM is a reference-based compressed format that can be substantially smaller than BAM but requires the reference to decompress.

The UCSC Genome Browser reads BAM directly when the file is coordinate-sorted and has a BAI index. BAM has become a general genome-browser format well beyond DNA alignment. The proBAM framework, for example, encodes peptide spectrum matches in BAM so that proteomics results can be displayed in genome browsers alongside genomic tracks [3]. That is a useful signal that BAM is a durable interchange format rather than a DNA-only artifact.

CRAM support in track hubs is inconsistent across browsers and versions. If your goal is a hub that works for the widest audience with the least troubleshooting, publish BAM.

### VCF and BCF

VCF is the text format for variant calls. It has a header block of `##` metadata lines, a `#CHROM` column header, and one row per variant. Coordinates in VCF are 1-based. BCF is the binary equivalent used by `bcftools`.

VCF is the common exchange format across the variant ecosystem. CoMutPlotter, a web tool for visualizing mutation landscapes in cancer cohorts, accepts VCF alongside MAF and TSV precisely because VCF is the format most variant callers emit [4]. For a track hub, the VCF must be bgzipped (not ordinary gzip) and indexed with tabix. An ordinary `gzip` file will not work because the browser cannot seek into it.

### BED and bigBed

BED is a tab-delimited interval format. The first three columns are chrom, chromStart, and chromEnd. Coordinates are 0-based and half-open, meaning the start is included and the end is excluded. A BED interval from 100 to 200 covers bases 101 through 200 in 1-based language. Extra columns add name, score, strand, thickStart, thickEnd, itemRgb, and block definitions, up to the BED12 layout and beyond.

bigBed is the indexed binary form of BED. The browser can fetch a single region from a bigBed file over HTTP range requests, which is why bigBed scales and plain BED does not. UCSC's own conversion utility, `bedToBigBed`, builds the index in one pass.

Annotation can also arrive as GFF3 or GTF, both 1-based. Tools such as BioNanoAnalyst emit GFF3 specifically so that questionable assembly regions can be imported into a local genome browser [5]. If your annotation is GFF3, convert it to BED or bigBed before publishing it as a hub track.

### Format summary

| Format | Content | Coordinate base | Required index | UCSC track type |
|--|--|--|--|--|
| FASTA | Reference sequence | 1-based | `.fai` for random access | Reference, not a track |
| FASTQ | Reads plus per-base quality | Not applicable | None | Not supported |
| BAM | Aligned reads | 0-based internally, displayed 1-based | `.bai` | `bam` |
| VCF | Variant calls | 1-based | `.tbi` or `.csi` | `vcf` |
| BED | Intervals | 0-based half-open | None, but must be sorted | `bed N` |
| bigBed | Indexed intervals | 0-based half-open | Built into the file | `bigBed N` |
| bigWig | Dense signal | 0-based | Built into the file | `bigWig` |

Dense coverage is usually published as bigWig rather than BED. FineMAV, a tool for prioritizing selected variants, writes its scores as bigWig because that format is supported by many genome browsers [6]. If you have per-base depth or a signal track, convert to bigWig instead of emitting millions of BED intervals.

## Before You Start: Decisions and Inventory

Four decisions shape the rest of the build.

**Assembly name.** Use the UCSC name, not the GRC name. GRCh38 is `hg38`, GRCh37 is `hg19`, GRCm38 is `mm10`, and GRCm39 is `mm39`. If your organism is not hosted by UCSC, you need an assembly hub rather than a track hub, and you must supply a twoBit reference and a chrom.sizes file.

**Data hosting.** Files must sit on an HTTPS server that supports HTTP range requests. The response header `Accept-Ranges: bytes` is the signal that the server can serve partial content. Python's built-in `http.server` does not support range requests, so it is fine for checking that `hub.txt` is reachable but not for testing bigBed or BAM tracks.

**File size strategy.** Small BED files under a few megabytes can be served as plain BED. Anything that will be queried repeatedly, or that exceeds roughly 50,000 intervals, should be bigBed. BAM and VCF are already binary or compressed and should stay in their native formats.

**Naming discipline.** Track names in `trackDb.txt` must be unique within the hub, must not contain spaces, and should be stable across releases. Short labels should fit under a track. Long labels should identify the sample, assay, and assembly.

A quick inventory command confirms that you have the tools you need:

```bash
for tool in samtools bgzip tabix bedToBigBed bigBedInfo fetchChromSizes; do
  printf "%-16s" "$tool"
  command -v "$tool" >/dev/null && echo "ok" || echo "missing"
done
```

Expected output on a working system:

```
samtools        ok
bgzip           ok
tabix           ok
bedToBigBed     ok
bigBedInfo      ok
fetchChromSizes ok
```

## UCSC Data Hub BAM VCF BED Step by Step

The walkthrough below uses `hg38` and a hub root at `/var/www/hub`. Adjust paths and the hostname to match your server.

### Step 1: Create the directory tree and chromosome sizes

```bash
mkdir -p /var/www/hub/hg38
cd /var/www/hub/hg38
fetchChromSizes hg38 > hg38.chrom.sizes
head -3 hg38.chrom.sizes
```

Expected output:

```
chr1	248956422
chr2	242193529
chr3	198295559
```

The chrom.sizes file is required by `bedToBigBed` and by assembly hubs. It is not required for a BAM or VCF track on an assembly that UCSC already hosts.

### Step 2: Sort and index the BAM

A BAM track needs coordinate sorting and a BAI index. The index file must be named either `sample.bam.bai` or `sample.bai` next to the BAM.

```bash
samtools quickcheck -v sample.bam && echo "BAM OK"
samtools sort -@ 8 -m 2G -o sample.sorted.bam sample.bam
samtools index -@ 8 sample.sorted.bam
samtools view -H sample.sorted.bam | grep '^@HD'
```

Expected output:

```
BAM OK
@HD	VN:1.6	SO:coordinate
```

The `SO:coordinate` tag is the proof that sorting worked. If you see `SO:unsorted` or no `@HD` line, the browser will fail to render the track correctly.

Check the index and the chromosome list:

```bash
samtools idxstats sample.sorted.bam | head -3
```

Expected output, with your own counts:

```
chr1	248956422	184203	0
chr2	242193529	171044	0
chr3	198295559	152337	0
```

The four columns are chromosome name, chromosome length, mapped reads, and unmapped reads. A zero in the mapped column for a chromosome you expect to be covered is a sign that the BAM was aligned to a different reference.

### Step 3: Compress and index the VCF

```bash
bgzip -@ 4 -k variants.vcf
tabix -p vcf variants.vcf.gz
tabix -l variants.vcf.gz | head
```

Expected output:

```
chr1
chr2
chr3
```

`bgzip -k` keeps the original VCF and writes `variants.vcf.gz`. `tabix -p vcf` writes `variants.vcf.gz.tbi`. For very large files or chromosomes longer than 512 Mb, add `-C` to build a CSI index, but confirm that your browser version reads CSI before you rely on it.

Test a region query to prove the index works:

```bash
tabix variants.vcf.gz chr1:1000000-1100000 | head -2
```

You should see zero or more variant rows in that window and no error. An error here means the compression or the index is wrong, not the hub.

### Step 4: Sort the BED and convert to bigBed

```bash
sort -k1,1 -k2,2n peaks.bed > peaks.sorted.bed
bedToBigBed -type=bed6+ peaks.sorted.bed hg38.chrom.sizes peaks.bigBed
bigBedInfo peaks.bigBed | head -12
```

Expected output, with your own counts:

```
#bigBed version: 4
#fileIndex: peaks.sorted.bed
#chromCount: 24
#itemCount: 48213
#basesCovered: 21458732
#meanCoverage: 0.007
#minVal: 0
#maxVal: 1000
```

If `bedToBigBed` reports that a chromosome is missing, your BED uses names such as `1` while `hg38.chrom.sizes` uses `chr1`. Fix the naming before converting. The browser will not silently rename chromosomes for you.

For a BED3 file, drop the `-type` flag:

```bash
bedToBigBed peaks.sorted.bed hg38.chrom.sizes peaks.bigBed
```

### Step 5: Write hub.txt

```bash
cat > /var/www/hub/hub.txt <<'EOF'
hub mylab
shortLabel My Lab Hub
longLabel My Laboratory Genome Browser Tracks
genomesFile genomes.txt
email bioinformatics@example.org
descriptionUrl https://example.org/hub/description.html
EOF
```

The `hub` name is an internal identifier. The `shortLabel` appears in the hub list. The `email` field is required and gives UCSC a contact if the hub misbehaves. The `descriptionUrl` is optional but strongly recommended because it gives readers provenance and methods.

### Step 6: Write genomes.txt

```bash
cat > /var/www/hub/genomes.txt <<'EOF'
genome hg38
trackDb hg38/trackDb.txt
EOF
```

The `trackDb` path is relative to the location of `genomes.txt`, not to the hub root and not to the web root. A wrong relative path is the most common reason a hub loads with no tracks.

### Step 7: Write trackDb.txt

```bash
cat > /var/www/hub/hg38/trackDb.txt <<'EOF'
track sampleBam
bigDataUrl https://example.org/hub/hg38/sample.sorted.bam
shortLabel Sample BAM
longLabel Sample alignment, hg38
type bam
visibility dense
color 0,0,178
bamColorMode strand

track variants
bigDataUrl https://example.org/hub/hg38/variants.vcf.gz
shortLabel Variants
longLabel Called variants, hg38
type vcf
visibility pack

track peaks
bigDataUrl https://example.org/hub/hg38/peaks.bigBed
shortLabel Peaks
longLabel ChIP-seq peaks, hg38
type bigBed 6
visibility squish
itemRgb on
EOF
```

Each track block is separated by a blank line. Comments start with `#`. Settings are one per line. The `bigDataUrl` can be absolute, as above, or relative to the trackDb file. Absolute URLs are easier to audit and less likely to break when files move between subdirectories.

### Step 8: Serve the files over HTTPS

An nginx location block that serves the hub and allows cross-origin reads looks like this:

```nginx
server {
    listen 443 ssl;
    server_name example.org;
    root /var/www;

    location /hub/ {
        add_header Access-Control-Allow-Origin "*";
    }
}
```

Nginx serves static files with range support by default. Apache does as well. Confirm the header:

```bash
curl -sI https://example.org/hub/hg38/peaks.bigBed | grep -i accept-ranges
```

Expected output:

```
accept-ranges: bytes
```

If that header is missing, bigBed and BAM tracks will fail even though `hub.txt` loads. Test partial content directly:

```bash
curl -s -r 0-99 -o /dev/null -w "%{http_code} %{size_download}\n" https://example.org/hub/hg38/peaks.bigBed
```

Expected output:

```
206 100
```

A `200` means the server ignored the range request and sent the whole file. A `403` means permissions or a web application firewall is blocking the request.

### Step 9: Load the hub in the UCSC Genome Browser

Open the Genome Browser, go to **My Data**, then **Track Hubs**, then the **My Hubs** tab. Paste `https://example.org/hub/hub.txt` into the URL field and add the hub. Select `hg38` as the genome and open a region where you know the data exists.

You can also share a direct link by appending the hub URL as a parameter to the browser gateway. The exact parameter name has changed across UCSC releases, so the stable approach is to give collaborators the `hub.txt` URL and the assembly name rather than a deep link.

### Step 10: Check that each track draws

Zoom to a region with coverage, for example `chr1:1,000,000-1,100,000`. The BAM track should show gray or colored alignment blocks. The VCF track should show variant marks in packed rows. The bigBed track should show intervals with the configured color.

If a track is listed but empty, the browser is usually reading the wrong assembly, the wrong coordinates, or a file with no records in that window. The verification section below walks through the checks in order.

## TrackDb Settings That Matter

Most trackDb lines are optional. A small set controls almost everything a reader will notice.

| Setting | Purpose | Example |
|--|--|--|
| `track` | Unique internal name, no spaces | `sampleBam` |
| `type` | Data format and BED subtype | `bam`, `vcf`, `bigBed 6` |
| `bigDataUrl` | HTTPS URL to the data file | `https://example.org/hub/hg38/peaks.bigBed` |
| `shortLabel` | Label shown next to the track | `Peaks` |
| `longLabel` | Description in the track list | `ChIP-seq peaks, hg38` |
| `visibility` | Default display mode | `dense`, `pack`, `squish`, `full` |
| `color` | RGB color for the track | `0,0,178` |
| `autoScale` | Rescale coverage to the window | `on` |
| `maxHeightPixels` | Maximum, default, and minimum height | `100:80:30` |
| `maxWindowToDraw` | Cap on window size for dense data | `1000000` |
| `itemRgb` | Use the BED RGB column | `on` |

Three settings deserve extra attention.

`type` must match the file. A bigBed file declared as `type bed 6` will fail because the browser expects text. A BAM declared as `type bigBed` will fail immediately. The subtype number in `bigBed 6` or `bigBed 12` tells the browser how many BED columns to expect.

`visibility` sets the first impression. `dense` collapses the track to a single row and is a good default for BAM because it keeps the page fast. `pack` and `squish` are better for VCF and BED because they show individual features without expanding every row. `full` should be reserved for tracks with few features.

`maxWindowToDraw` protects the browser from trying to render millions of features at whole-genome scale. When the user zooms out past the cap, the track draws as a summary or disappears. Set it deliberately rather than leaving it to the default.

For BAM tracks, `bamColorMode` accepts `strand`, `gray`, `tag`, and `off`. `strand` colors reads by strand and is the most informative default for RNA-seq. `gray` is better for DNA alignments where strand is not meaningful.

## Common Errors and Exact Fixes

**`curl: (22) The requested URL returned error: 404`** when fetching `hub.txt`. The path is wrong, the file is outside the web root, or a rewrite rule is intercepting the request. Check with `curl -I` from the same network path the browser uses.

**The hub loads but shows no genomes.** `genomesFile` in `hub.txt` points to a file that does not exist, or the path is relative to the wrong directory. Confirm that `genomes.txt` sits next to `hub.txt`.

**The genome loads but no tracks appear.** The `trackDb` path in `genomes.txt` is wrong, or the genome name does not match the assembly the user selected. Open `https://example.org/hub/hg38/trackDb.txt` directly in a browser to confirm it is reachable.

**`[E::idx_find_and_load] Could not retrieve index file for 'sample.bam'`** from samtools. The BAI is missing, or it is named in a way samtools does not recognize. Run `samtools index sample.sorted.bam` and confirm the file is `sample.sorted.bam.bai`.

**The BAM track draws nothing and the BAI exists.** The BAM is not coordinate-sorted, or it was aligned to a different assembly. Check `samtools view -H` for `SO:coordinate` and check `samtools idxstats` for reads on the chromosomes you expect.

**`[tabix] the index file is older than the data file`** when querying a VCF. The `.tbi` was built before the `.vcf.gz` was replaced. Re-run `tabix -p vcf variants.vcf.gz`.

**The VCF track is empty but the file has variants.** The file was compressed with `gzip` instead of `bgzip`, so the browser cannot seek into it. Recompress with `bgzip` and rebuild the tabix index.

**`bedToBigBed` reports a chromosome that is not in the chrom.sizes file.** Your BED and your chrom.sizes use different naming conventions, typically `1` versus `chr1`. Convert the BED names or use a matching chrom.sizes file. Do not mix.

**The bigBed track loads but never draws at any zoom level.** The server is not honoring range requests. Confirm `Accept-Ranges: bytes` and a `206` response to a ranged `curl`.

**The browser console shows `Mixed Content: The page at 'https://genome.ucsc.edu/' was loaded over HTTPS, but requested an insecure resource 'http://example.org/...'`.** The hub is served over HTTP. Move it to HTTPS. Modern browsers block the request before it reaches your server.

**`403 Forbidden` on data files but `200` on `hub.txt`.** File permissions or a web application firewall rule differs between text files and binary files. Check the server error log and the file mode.

**A track name with a space or punctuation breaks the hub.** Track names must be tokens. Rename the track and keep the human-readable text in `shortLabel` and `longLabel`.

**The hub works for you but not for a collaborator.** The collaborator's network blocks outbound HTTPS, the server requires a client certificate, or the URL uses a hostname that only resolves inside your institution. Test from outside your network before sharing.

## Verifying the Hub

Verification proceeds from the outside in, because each layer depends on the one before it.

1. Fetch `hub.txt`, `genomes.txt`, and `trackDb.txt` with `curl` and confirm each returns `200`.
2. Confirm `Accept-Ranges: bytes` on each data file and a `206` response to a one-byte range request.
3. Run `samtools quickcheck -v` on the BAM, `tabix -l` on the VCF, and `bigBedInfo` on the bigBed. Each tool validates its own format more strictly than the browser will.
4. Compare record counts. `samtools idxstats` gives mapped reads per chromosome, `bcftools index -n variants.vcf.gz` gives the variant count, and `bigBedInfo` gives the interval count. Write these numbers down so that you can detect a truncated upload later.
5. Load the hub in a private browser window with no cached session, navigate to a known region, and confirm that each track draws the expected feature at the expected coordinate.
6. Ask one colleague on a different network to load the same URL. This catches DNS, firewall, and certificate issues that never appear locally.

A compact verification script:

```bash
HUB=https://example.org/hub
for f in hub.txt genomes.txt hg38/trackDb.txt hg38/peaks.bigBed hg38/variants.vcf.gz hg38/variants.vcf.gz.tbi hg38/sample.sorted.bam hg38/sample.sorted.bam.bai; do
  code=$(curl -s -o /dev/null -w "%{http_code}" "$HUB/$f")
  echo "$code $f"
done
```

Every line should read `200`. A single `404` identifies the exact file to fix.

This kind of staged readiness check mirrors what mature data pipelines do before analysis. Automated readiness assessment tools verify file formats, metadata completeness, and column consistency before downstream work begins [7]. A hub benefits from the same discipline because a missing index or a mismatched chromosome name produces a silent failure rather than a crash.

## Tips for a Fast, Reliable Hub

**Prefer bigBed over BED for anything you will query repeatedly.** A plain BED track forces the browser to download the whole file. A bigBed track fetches only the visible window.

**Prefer bigWig over BED for coverage.** Millions of one-base intervals are a sign that the data should be a signal track. FineMAV's choice to emit bigWig reflects the same reasoning: genome browsers handle dense signal efficiently in that format [6].

**Keep compression moderate.** `bgzip` and `samtools` default compression is a reasonable trade between size and CPU. Higher compression levels save bandwidth but slow the first paint. For BAM, `samtools sort -l 6` is often enough.

**Use relative paths inside the hub and absolute URLs in `bigDataUrl`.** Relative paths make the hub portable between staging and production. Absolute data URLs make it obvious where the bytes come from when something breaks.

**Version the directory, not the file.** Publish `hub/v1/`, `hub/v2/`, and so on, and give collaborators the versioned `hub.txt`. Replacing a file in place invalidates caches and tabix indexes in ways that are hard to debug.

**Set `maxWindowToDraw` on every dense track.** It is the difference between a responsive page and a browser tab that stalls when a user clicks the whole-genome view.

**Document the assembly and the coordinate convention in `descriptionUrl`.** Readers need to know whether your BED is 0-based, which callers produced the VCF, and which reference build the BAM used. This is metadata work, and metadata is often the difference between a reusable hub and a one-off link.

**Keep the hub configuration under version control.** The three text files are small. A Git repository gives you a history of every track change and an easy rollback.

## Sharing, Metadata, and Access Control

A track hub is a public artifact unless you put it behind network controls. The configuration files carry no authentication. Anyone who learns the `hub.txt` URL can load every track that the hub points to. Plan for that from the start.

For public data, publish a `descriptionUrl` page that states the organism, assembly, assay, processing pipeline, and contact. Link to the paper or preprint. This is the same provenance discipline that data warehouses enforce when they ingest heterogeneous sources through structured mappings [8]. The hub is smaller, but the principle is identical.

For pre-publication data, host the hub on an internal network or behind an authenticated reverse proxy. Do not rely on an unguessable filename as your only control. If you need to share with external collaborators, a signed URL from an object store with a short expiry is a better mechanism than a permanent open path.

For controlled-access human data, a public hub is not appropriate. The BAM contains read-level information, and the VCF may contain genotypes. Both are identifiable in combination with other data. Use a controlled-access repository and a local browser session instead.

Relational databases and structured data models solve some of these problems for large programs [9], and flexible schema designs have been proposed for heterogeneous systems biology data [10]. A track hub does not attempt any of that. It is deliberately minimal. Treat it as a presentation layer over files that are already governed elsewhere.

## Common Mistakes and Limitations

**Mixing coordinate conventions.** BED is 0-based half-open. VCF is 1-based. GFF3 is 1-based. A BED interval that starts at 100 and ends at 200 covers the same bases as a VCF record at position 101 through 200. Off-by-one errors are the most common reason a peak looks shifted relative to a variant.

**Forgetting the index.** A BAM without a BAI, or a VCF compressed with plain `gzip`, will fail even if every path and setting is correct. Indexes are not optional for remote tracks.

**Assuming the browser renames chromosomes.** It does not. `chr1` and `1` are different sequences to a track hub. Pick one convention and apply it to every file, including the chrom.sizes file.

**Using an assembly nickname that UCSC does not recognize.** `GRCh38` is not a UCSC genome name. Use `hg38`. For a non-model organism, build an assembly hub with a twoBit file rather than forcing the data into a mismatched assembly.

**Publishing raw FASTQ or FASTA as a track.** Neither is a coordinate-indexed feature file. Align FASTQ to a FASTA reference and publish the resulting BAM or bigWig.

**Leaving `visibility full` on a BAM track.** A full-height BAM track with thousands of reads at a locus makes the page slow and the signal hard to read. Use `dense` or `pack` and let readers expand what they need.

**Ignoring `maxWindowToDraw`.** Without a cap, a dense track can attempt to render an entire chromosome. The browser will either drop the track or stall.

**Testing only on localhost.** A local server without range support, or a local hostname that resolves only on your machine, will pass your checks and fail for everyone else. Test over the same HTTPS path that collaborators will use.

**Treating the hub as storage.** If you delete the BAM, the track disappears. The hub does not cache data on UCSC's side. Back up the underlying files separately.

**Expecting access control that the format does not provide.** Track hubs have no user accounts, no per-track permissions, and no audit log. Privacy must come from the hosting layer.

**Assuming that a working hub is a validated dataset.** The browser will display whatever you point it at. It does not check that the BAM was aligned to the correct reference, that the VCF passed quality filtering, or that the BED intervals are biologically meaningful. Quality control belongs upstream. QC frameworks for sequencing data generate dedicated reports for exactly this reason [11], and a hub should link to those reports rather than replace them.

**Overlooking alternative renderers.** A hub is not the only way to show genomic features. Circular genome figures, for example, can display SNPs and indels relative to a reference with a dedicated renderer [12]. Choose the visualization that fits the question rather than forcing every dataset into a linear browser track.

Individual datasets vary, and a hub that works for one project may need a different assembly, index type, or hosting model for another.

## Frequently Asked Questions

### Do I need my own web server to use a UCSC data hub?

Yes, for any hub that other people will load. The configuration files and data files must be reachable over HTTPS. You can test a hub from a local server, but Python's built-in `http.server` does not support range requests, so binary tracks will not render reliably.

### Should I upload BED or bigBed to a track hub?

Use bigBed for anything beyond a small file. bigBed is indexed and the browser fetches only the visible window, while plain BED forces a full download. Plain BED is acceptable for a few thousand intervals during early testing.

### Why does my BAM track appear empty in the UCSC Genome Browser?

The usual causes are a missing BAI, a BAM that is not coordinate-sorted, a mismatch between the BAM's reference and the selected assembly, or a server that does not honor range requests. Check `samtools quickcheck`, the `SO:coordinate` header tag, and the `Accept-Ranges` response header in that order.

### What is the difference between a track hub and an assembly hub?

A track hub adds tracks to an assembly that UCSC already hosts, such as `hg38`. An assembly hub supplies a new reference genome, including a twoBit sequence file and a chrom.sizes file, and then adds tracks to that custom assembly.

### Can I view FASTQ or FASTA files as tracks?

No. FASTA is a reference sequence and FASTQ is raw reads with quality scores. Neither is a coordinate-indexed feature file. Align FASTQ reads to a FASTA reference, then publish the resulting BAM or bigWig.

### How do I make a VCF file display correctly?

Compress it with `bgzip`, not `gzip`, and index it with `tabix -p vcf`. Declare the track as `type vcf`. Confirm the index is adjacent to the compressed file and that the VCF's chromosome names match the assembly.

### Does UCSC host my BAM, VCF, and BED files?

No. UCSC reads your configuration and streams byte ranges from your server. The files stay under your control, and deleting or moving them breaks the tracks.

### Can I restrict access to my data hub?

The track hub format has no built-in authentication. Restrict access at the hosting layer with an internal network, an authenticated reverse proxy, or short-lived signed URLs. Do not treat an unguessable path as a security control.

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "FAQPage",
  "mainEntity": [
    {
      "@type": "Question",
      "name": "Do I need my own web server to use a UCSC data hub?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "Yes, for any hub that other people will load. The configuration files and data files must be reachable over HTTPS. You can test a hub from a local server, but Python's built-in http.server does not support range requests, so binary tracks will not render reliably."
      }
    },
    {
      "@type": "Question",
      "name": "Should I upload BED or bigBed to a track hub?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "Use bigBed for anything beyond a small file. bigBed is indexed and the browser fetches only the visible window, while plain BED forces a full download. Plain BED is acceptable for a few thousand intervals during early testing."
      }
    },
    {
      "@type": "Question",
      "name": "Why does my BAM track appear empty in the UCSC Genome Browser?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "The usual causes are a missing BAI, a BAM that is not coordinate-sorted, a mismatch between the BAM reference and the selected assembly, or a server that does not honor range requests. Check samtools quickcheck, the SO:coordinate header tag, and the Accept-Ranges response header in that order."
      }
    },
    {
      "@type": "Question",
      "name": "What is the difference between a track hub and an assembly hub?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "A track hub adds tracks to an assembly that UCSC already hosts, such as hg38. An assembly hub supplies a new reference genome, including a twoBit sequence file and a chrom.sizes file, and then adds tracks to that custom assembly."
      }
    },
    {
      "@type": "Question",
      "name": "Can I view FASTQ or FASTA files as tracks?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "No. FASTA is a reference sequence and FASTQ is raw reads with quality scores. Neither is a coordinate-indexed feature file. Align FASTQ reads to a FASTA reference, then publish the resulting BAM or bigWig."
      }
    },
    {
      "@type": "Question",
      "name": "How do I make a VCF file display correctly?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "Compress it with bgzip, not gzip, and index it with tabix -p vcf. Declare the track as type vcf. Confirm the index is adjacent to the compressed file and that the VCF chromosome names match the assembly."
      }
    },
    {
      "@type": "Question",
      "name": "Does UCSC host my BAM, VCF, and BED files?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "No. UCSC reads your configuration and streams byte ranges from your server. The files stay under your control, and deleting or moving them breaks the tracks."
      }
    },
    {
      "@type": "Question",
      "name": "Can I restrict access to my data hub?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "The track hub format has no built-in authentication. Restrict access at the hosting layer with an internal network, an authenticated reverse proxy, or short-lived signed URLs. Do not treat an unguessable path as a security control."
      }
    }
  ]
}
</script>

## Sources

1. [Online resources for genomic analysis using high-throughput sequencing.](https://pubmed.ncbi.nlm.nih.gov/25655493/)
2. [Setting Up the JBrowse 2 Genome Browser.](https://pubmed.ncbi.nlm.nih.gov/39126338/)
3. [proBAMsuite, a Bioinformatics Framework for Genome-Based Representation and Analysis of Proteomics Data.](https://pubmed.ncbi.nlm.nih.gov/26657539/)
4. [CoMutPlotter: a web tool for visual summary of mutations in cancer cohorts.](https://pubmed.ncbi.nlm.nih.gov/31296206/)
5. [BioNanoAnalyst: a visualisation tool to assess genome assembly quality using BioNano data.](https://pubmed.ncbi.nlm.nih.gov/28666410/)
6. [Prioritising positively selected variants in whole-genome sequencing data using FineMAV.](https://pubmed.ncbi.nlm.nih.gov/34922440/)
7. [ReduXis: A Comprehensive Framework for Robust Event-Based Modeling and Profiling of High-Dimensional Biomedical Data.](https://pubmed.ncbi.nlm.nih.gov/41009540/)
8. [From Spreadsheets and Bespoke Models to Enterprise Data Warehouses: GPT-enabled Clinical Data Ingestion into i2b2.](https://pubmed.ncbi.nlm.nih.gov/40321272/)
9. [Databases to Efficiently Manage Medium Sized, Low Velocity, Multidimensional Data in Tissue Engineering.](https://pubmed.ncbi.nlm.nih.gov/31814616/)
10. [Ultra-Structure database design methodology for managing systems biology data and analyses.](https://pubmed.ncbi.nlm.nih.gov/19691849/)
11. [QCatch: a framework for quality control assessment and analysis of single-cell sequencing data.](https://pubmed.ncbi.nlm.nih.gov/41987571/)
12. [Circleator: flexible circular visualization of genome-associated data with BioPerl and SVG.](https://pubmed.ncbi.nlm.nih.gov/25075113/)