This vignette walks through the main features of {risAT} using concrete examples. For a full parameter reference, see the function reference.
{risAT} provides a tidyverse-friendly interface to the Austrian RIS (Rechtsinformationssystem)
Open Government Data API v2.6. It covers the /Judikatur
endpoint — case law from all nine supported court applications — and is
designed for reproducible legal research.
First search
The fastest way in is a court-specific wrapper. Each wrapper targets a single court and provides typed, validated arguments. Let’s retrieve Administrative Court (VwGH) decisions on housing law (Baurecht):
library(risAT)
results <- ris_search_vwgh(query = "Baurecht")
results#> # A tibble: 9,637 × 5
#> id document_type case_number decision_date vwgh_decision_type
#> <chr> <chr> <chr> <chr> <chr>
#> 1 JWT_2025050017_20… Text Ro 2025/05… 2026-05-06 Beschluss
#> 2 JWR_2025050017_20… Rechtssatz Ro 2025/05… 2026-05-06 Beschluss
#> 3 JWR_2025050017_20… Rechtssatz Ro 2025/05… 2026-05-06 Beschluss
#> 4 JWT_2025070002_20… Text Ro 2025/07… 2026-04-22 Erkenntnis
#> 5 JWT_2023050255_20… Text Ra 2023/05… 2026-04-10 Beschluss
#> 6 JWR_2023050255_20… Rechtssatz Ra 2023/05… 2026-04-10 Beschluss
#> 7 JWR_2023050255_20… Rechtssatz Ra 2023/05… 2026-04-10 Beschluss
#> 8 JWT_2025050071_20… Text Ra 2025/05… 2026-04-10 Beschluss
#> 9 JWR_2025050071_20… Rechtssatz Ra 2025/05… 2026-04-10 Beschluss
#> 10 JWT_2025050145_20… Text Ra 2025/05… 2026-03-27 Erkenntnis
#> # ℹ 9,627 more rows
All search functions return a tibble — one row per document. The most frequently used columns are:
| Column | Description |
|---|---|
id |
Unique RIS document identifier |
case_number |
Business number (Geschäftszahl) |
decision_date |
Date of the decision |
document_type |
Rechtssatz or Text (full decision) |
content_urls |
List-column of download links |
app_metadata |
List-column of court-specific and response metadata |
Filtering results
All wrappers share a common set of filter arguments. Date ranges
follow ISO 8601 ("YYYY-MM-DD"), and
decision_type accepts the German API values and lowercase
aliases.
results <- ris_search_vwgh(
query = "Asyl",
decision_date_from = "2023-01-01",
decision_date_to = "2024-12-31",
decision_type = "Erkenntnis"
)
nrow(results)#> [1] 584
The in_ris_since argument is a convenient shortcut for
recently published documents:
recent <- ris_search_vwgh(in_ris_since = "one_month")
nrow(recent)#> [1] 855
Decisions over time
Because results come back as a tidy tibble, downstream analysis with {dplyr} and {ggplot2} is straightforward. Below we retrieve VwGH asylum decisions from 2019 to 2024 and visualise the yearly count.
df_asyl <- ris_search_vwgh(
query = "Asyl",
decision_date_from = "2019-01-01",
decision_date_to = "2024-12-31",
decision_type = "Erkenntnis"
)
library(dplyr)
library(ggplot2)
library(lubridate)
df_asyl |>
mutate(year = year(as.Date(decision_date))) |>
count(year) |>
ggplot(aes(x = year, y = n)) +
geom_col(fill = "#2E4057") +
scale_x_continuous(breaks = 2019:2024) +
scale_y_continuous(expand = expansion(mult = c(0, 0.05))) +
labs(
title = "VwGH decisions on asylum law by year",
subtitle = "Search term: 'Asyl', decision type: Erkenntnis, 2019–2024.",
caption = "Data: RIS OGD API v2.6; retrieved via {risAT}.",
x = NULL, y = NULL
) +
theme_minimal() +
theme(
plot.title = element_text(face = "bold"),
plot.title.position = "plot",
plot.subtitle = element_text(color = "grey40", margin = margin(b = 10)),
plot.caption = element_text(color = "grey50", size = rel(0.8)),
panel.grid.major.x = element_blank(),
panel.grid.minor = element_blank()
)
Court-specific wrappers
risAT provides wrappers for all nine Judikatur applications:
| Court | Function |
|---|---|
| VfGH (Constitutional Court) | ris_search_vfgh() |
| VwGH (Administrative Court) | ris_search_vwgh() |
| Justiz (OGH, OLG, LG, BG) | ris_search_justiz() |
| BVwG (Federal Administrative Court) | ris_search_bvwg() |
| LVwG (State Administrative Courts) | ris_search_lvwg() |
| DSK / DSB (Data Protection) | ris_search_dsk() |
| DOK (Disciplinary Bodies) | ris_search_dok() |
| PVAK (Staff Representation) | ris_search_pvak() |
| GBK (Equal Treatment Commission) | ris_search_gbk() |
Some wrappers expose court-specific parameters.
ris_search_justiz() lets you filter by court and legal
area:
results_ogh <- ris_search_justiz(
query = "Schadenersatz",
court = "OGH",
legal_area = "Zivilrecht"
)
nrow(results_ogh)#> [1] 9409
ris_search_lvwg() restricts results to a single state
administrative court via federal_state. English state names
are accepted:
results_wien <- ris_search_lvwg(
federal_state = "Vienna", # also accepted: "Wien"
decision_type = "Erkenntnis"
)
nrow(results_wien)#> [1] 9602
ris_search_gbk() filters Equal Treatment Commission
decisions by commission, senate, and discrimination ground — English
aliases are supported:
results_gbk <- ris_search_gbk(
discrimination_ground = "gender", # "Geschlecht"
commission = "private_sector" # "Gleichbehandlungskommission"
)
nrow(results_gbk)#> [1] 284
VfGH: constitutional court decisions
The VfGH wrapper defaults to legal principles (Rechtssätze)
rather than full decision texts — the most common use case for
constitutional court research. Toggle via
search_legal_principles and
search_decision_text:
# Default: Rechtssätze (RS)
results_vfgh <- ris_search_vfgh(query = "Grundrecht")
nrow(results_vfgh)
# Request full decision texts instead
results_vfgh_et <- ris_search_vfgh(
query = "Grundrecht",
search_legal_principles = FALSE,
search_decision_text = TRUE
)#> [1] 1530
Verifying results with echo
Setting echo = TRUE prints the search parameters and a
direct link to the same results on the official RIS website. This is
useful for:
- Verification — open the URL in a browser and compare with the API results.
- Sharing — paste the URL to share a query with colleagues who don’t use R.
- Exploration — browse results on the RIS website before refining your query.
results <- ris_search_vwgh(
query = "Baurecht",
decision_date_from = "2024-01-01",
echo = TRUE
)The printed output shows the total hit count and a clickable RIS URL that preserves all filter parameters.
Working with list-columns
Two columns contain richer nested data.
content_urls — download links
Each element of content_urls is a character vector of
URLs pointing to the document in different formats (XML, HTML, RTF,
PDF):
results$content_urls[[1]]#> [1] "https://www.ris.bka.gv.at/Dokumente/Vwgh/JWT_2025050017_20260506J00/JWT_2025050017_20260506J00.xml"
#> [2] "https://www.ris.bka.gv.at/Dokumente/Vwgh/JWT_2025050017_20260506J00/JWT_2025050017_20260506J00.html"
#> [3] "https://www.ris.bka.gv.at/Dokumente/Vwgh/JWT_2025050017_20260506J00/JWT_2025050017_20260506J00.rtf"
#> [4] "https://www.ris.bka.gv.at/Dokumente/Vwgh/JWT_2025050017_20260506J00/JWT_2025050017_20260506J00.pdf"
To extract all PDF URLs across results, filter by file extension:
library(purrr)
pdf_urls <- results |>
mutate(
pdf_url = map_chr(
content_urls,
\(x) {
hit <- x[grepl("\\.pdf$", x, ignore.case = TRUE)]
if (length(hit)) hit[[1]] else NA_character_
}
)
) |>
filter(!is.na(pdf_url)) |>
select(case_number, decision_date, pdf_url)
pdf_urls#> # A tibble: 9,637 × 3
#> case_number decision_date pdf_url
#> <chr> <chr> <chr>
#> 1 Ro 2025/05/0017 2026-05-06 https://www.ris.bka.gv.at/Dokumente/Vwgh/JWT_2…
#> 2 Ro 2025/05/0017 2026-05-06 https://www.ris.bka.gv.at/Dokumente/Vwgh/JWR_2…
#> 3 Ro 2025/05/0017 2026-05-06 https://www.ris.bka.gv.at/Dokumente/Vwgh/JWR_2…
#> 4 Ro 2025/07/0002 2026-04-22 https://www.ris.bka.gv.at/Dokumente/Vwgh/JWT_2…
#> 5 Ra 2023/05/0255 2026-04-10 https://www.ris.bka.gv.at/Dokumente/Vwgh/JWT_2…
#> 6 Ra 2023/05/0255 2026-04-10 https://www.ris.bka.gv.at/Dokumente/Vwgh/JWR_2…
#> 7 Ra 2023/05/0255 2026-04-10 https://www.ris.bka.gv.at/Dokumente/Vwgh/JWR_2…
#> 8 Ra 2025/05/0071 2026-04-10 https://www.ris.bka.gv.at/Dokumente/Vwgh/JWT_2…
#> 9 Ra 2025/05/0071 2026-04-10 https://www.ris.bka.gv.at/Dokumente/Vwgh/JWR_2…
#> 10 Ra 2025/05/0145 2026-03-27 https://www.ris.bka.gv.at/Dokumente/Vwgh/JWT_2…
#> # ℹ 9,627 more rows
app_metadata — court-specific fields and response
context
Court-specific fields and pagination context are nested in
app_metadata. Use tidyr::unnest_wider() to
bring them to the top level:
library(tidyr)
results |>
select(id, case_number, app_metadata) |>
unnest_wider(app_metadata) |>
glimpse()#> Rows: 9,637
#> Columns: 6
#> $ id <chr> "JWT_2025050017_20260506J00", "JWR_2025050017_20260506J02"…
#> $ case_number <chr> "Ro 2025/05/0017", "Ro 2025/05/0017", "Ro 2025/05/0017", "…
#> $ response <list> [NA, 9637, 1, 100], [NA, 9637, 1, 100], [NA, 9637, 1, 100…
#> $ technisch <list> ["JWT_2025050017_20260506J00", "Vwgh", "Verwaltungsgerich…
#> $ allgemein <list> ["2026-06-02", "2026-06-02", "https://www.ris.bka.gv.at/D…
#> $ request <list> ["/Judikatur", "Vwgh", 1, "OneHundred", "https://www.ris.…
The response sub-list contains pagination context (total
hits, page number) and request records the exact API
parameters sent:
# Total hits reported by the API
results$app_metadata[[1]]$response$hits
# Page context
results$app_metadata[[1]]$response$page_number
results$app_metadata[[1]]$response$page_size#> 9637
#> 1
#> 100
The two-step pattern
Under the hood every wrapper calls two lower-level functions:
-
ris_req_case_law()— builds anhttr2request object (no network call). -
ris_perform_case_law()— executes the request with automatic pagination.
Use these directly for more control — to inspect the URL before sending, or to target application codes not covered by a named wrapper:
# Build — no network call yet
req <- ris_req_case_law(
application = "Vwgh",
query = "Baurecht"
)
# Inspect the URL before sending
req$url
# Execute — fetches all pages automatically
results <- ris_perform_case_law(req)
nrow(results)#> https://data.bka.gv.at/ris/api/v2.6/Judikatur?Applikation=Vwgh&Suchworte=Baurecht&SortierungSortDirection=Descending&SortierungSortedByColumn=Datum&DokumenttypSucheInEntscheidungstexten=true&DokumenttypSucheInRechtssaetzen=true&Seitennummer=1&DokumenteProSeite=OneHundred
