The hardware and bandwidth for this mirror is donated by METANET, the Webhosting and Full Service-Cloud Provider.
If you wish to report a bug, or if you are interested in having us mirror your free-software or open-source project, please feel free to contact us at mirror[@]metanet.ch.

Tracking state GDP components with IBGE data

Overview

This vignette demonstrates how to query IBGE aggregate tables that serve as short-term tracking indicators for state-level GDP components — particularly in services, retail, manufacturing, and construction.

The workflow is always the same:

  1. Inspect metadata with ibge_metadata() to discover available variables, classifications, and categories.
  2. Fetch data with ibge_variables(), specifying aggregate, variable, classification, localities, and periods.
  3. Post-process the value column with parse_ibge_value() and convert period codes to proper dates.

Note on value: the IBGE API may return special symbols ("-", "..", "...", "X") instead of numbers. Always use parse_ibge_value() to convert reliably.

Setup

library(ibger)
library(dplyr)
library(tidyr)
library(ggplot2)
library(lubridate)
library(stringr)

Helper: convert period codes to dates

IBGE returns periods as character codes: "202501" for monthly data (January 2025) and "202501" for quarterly data (Q1 2025). We need format-specific converters:

# Monthly periods: "202501" -> 2025-01-01
period_to_monthly <- function(x) ym(x)

# Quarterly periods: "202501" -> 2025-01-01
# lubridate::yq() expects "2025.1", so we reformat first
period_to_quarterly <- function(x) {
  yr <- substr(x, 1, 4)
  qt <- as.integer(substr(x, 5, 6))
  as.Date(paste0(yr, "-", qt * 3 - 2, "-01"))
}

1) IPCA (7060) — Health insurance

The IPCA (consumer price index) aggregate 7060 is the main source for inflation tracking. Here we compare the general index against the health insurance sub-item for the Recife Metropolitan Area.

1.1 Discovering the right IDs

meta_7060 <- ibge_metadata(7060)

# Find classification categories matching "Plano" (health plan) or "Índice" (index)
unnest(meta_7060$classifications, categories) |>
  filter(str_detect(category_name, "Plano|Índice")) |>
  select(id, category_id, category_name, category_level)
#> # A tibble: 5 × 4
#>   id    category_id category_name                    category_level
#>   <chr> <chr>       <chr>                            <chr>         
#> 1 315   7169        Índice geral                     0             
#> 2 315   7695        6203.Plano de saúde              3             
#> 3 315   7696        6203001.Plano de saúde           4             
#> 4 315   47668       9101002.Plano de telefonia fixa  4             
#> 5 315   47669       9101008.Plano de telefonia móvel 4

# Available variables
meta_7060$variables
#> # A tibble: 4 × 3
#>   id    name                                  unit 
#>   <chr> <chr>                                 <chr>
#> 1 63    IPCA - Variação mensal                %    
#> 2 69    IPCA - Variação acumulada no ano      %    
#> 3 2265  IPCA - Variação acumulada em 12 meses %    
#> 4 66    IPCA - Peso mensal                    %

Reading the output:

1.2 Fetching the data

ipca_health <- ibge_variables(
  aggregate = 7060,
  variable = 63,                          # IPCA - Monthly variation
  periods = -12,
  classification = list(
    "315" = c("7169", "7695")             # General index + Health insurance
  ),
  localities = "N7[2601]"                 # Recife Metropolitan Area
) |>
  mutate(
    value  = parse_ibge_value(value),
    period = period_to_monthly(period)
  ) |>
  select(period, classification_315, locality_name, value)

1.3 Wide format for inspection

ipca_health |>
  pivot_wider(
    id_cols    = c(period, locality_name),
    names_from = classification_315,
    values_from = value
  ) |>
  arrange(desc(period))
#> # A tibble: 12 × 4
#>    period     locality_name `Índice geral` `6203.Plano de saúde`
#>    <date>     <chr>                  <dbl>                 <dbl>
#>  1 2026-06-01 Recife (PE)            -0.04                  0.34
#>  2 2026-05-01 Recife (PE)             0.95                  0.5 
#>  3 2026-04-01 Recife (PE)             0.82                  0.5 
#>  4 2026-03-01 Recife (PE)             1.1                   0.5 
#>  5 2026-02-01 Recife (PE)             0.73                  0.5 
#>  6 2026-01-01 Recife (PE)             0.28                  0.5 
#>  7 2025-12-01 Recife (PE)             0.54                  0.5 
#>  8 2025-11-01 Recife (PE)            -0.08                  0.5 
#>  9 2025-10-01 Recife (PE)             0.17                  0.5 
#> 10 2025-09-01 Recife (PE)             0.56                  0.5 
#> 11 2025-08-01 Recife (PE)            -0.24                  0.5 
#> 12 2025-07-01 Recife (PE)             0.32                  0.38

1.4 Plot

ipca_health |>
  ggplot(aes(period, value, color = classification_315)) +
  geom_line() +
  geom_point() +
  labs(
    title = "IPCA — Health insurance vs General index",
    subtitle = "Recife Metropolitan Area, monthly variation (%)",
    x = NULL, y = "Monthly variation (%)", color = NULL
  ) +
  theme_minimal() +
  theme(legend.position = "bottom")
plot of chunk unnamed-chunk-6
plot of chunk unnamed-chunk-6

2) IPCA (7060) — Vehicle insurance

Same logic — only the category changes in classification "315".

# Find category ID for "Seguro" (insurance)
unnest(meta_7060$classifications, categories) |>
  filter(str_detect(category_name, "Seguro|Índice")) |>
  select(id, category_id, category_name)
#> # A tibble: 2 × 3
#>   id    category_id category_name                       
#>   <chr> <chr>       <chr>                               
#> 1 315   7169        Índice geral                        
#> 2 315   7643        5102005.Seguro voluntário de veículo
ipca_vehicle_ins <- ibge_variables(
  aggregate = 7060,
  variable = 63,
  periods = -12,
  classification = list("315" = c("7169", "7643")),  # General + Vehicle insurance
  localities = "N7[2601]"
) |>
  mutate(
    value  = parse_ibge_value(value),
    period = period_to_monthly(period)
  ) |>
  select(period, classification_315, locality_name, value)
ipca_vehicle_ins |>
  ggplot(aes(period, value, color = classification_315)) +
  geom_line() +
  geom_point() +
  labs(
    title = "IPCA — Vehicle insurance vs General index",
    subtitle = "Recife Metropolitan Area, monthly variation (%)",
    x = NULL, y = "Monthly variation (%)", color = NULL
  ) +
  theme_minimal() +
  theme(legend.position = "bottom")
plot of chunk unnamed-chunk-9
plot of chunk unnamed-chunk-9

3) PMS (8693) — Transportation and postal services

The Monthly Survey of Services (PMS) aggregate 8693 is a proxy for service-sector activity. Here we filter by:

meta_8693 <- ibge_metadata(8693)

# Browse classifications and categories
unnest(meta_8693$classifications, categories)
#> # A tibble: 8 × 6
#>   id    name              category_id category_name category_unit category_level
#>   <chr> <chr>             <chr>       <chr>         <chr>         <chr>         
#> 1 11046 Tipos de índice   56725       Índice de re… <NA>          0             
#> 2 11046 Tipos de índice   56726       Índice de vo… <NA>          0             
#> 3 12355 Atividades de se… 107071      Total         <NA>          0             
#> 4 12355 Atividades de se… 106869      1. Serviços … <NA>          1             
#> 5 12355 Atividades de se… 106874      2. Serviços … <NA>          1             
#> 6 12355 Atividades de se… 31399       3. Serviços … <NA>          1             
#> 7 12355 Atividades de se… 106876      4. Transport… <NA>          1             
#> 8 12355 Atividades de se… 31426       5. Outros se… <NA>          1
meta_8693$variables
#> # A tibble: 6 × 3
#>   id    name                                                               unit 
#>   <chr> <chr>                                                              <chr>
#> 1 7167  PMS - Número-índice (2022=100)                                     Núme…
#> 2 7168  PMS - Número-índice com ajuste sazonal (2022=100)                  Núme…
#> 3 11623 PMS - Variação mês/mês imediatamente anterior, com ajuste sazonal… %    
#> 4 11624 PMS - Variação mês/mesmo mês do ano anterior (M/M-12)              %    
#> 5 11625 PMS - Variação acumulada no ano (em relação ao mesmo período do a… %    
#> 6 11626 PMS - Variação acumulada em 12 meses (em relação ao período anter… %
pms_transport <- ibge_variables(
  aggregate = 8693,
  variable = 7167,                          # Index number (2022 = 100)
  periods = -12,
  classification = list(
    "11046" = "all",                        # All index types (revenue + volume)
    "12355" = "106876"                      # Transportation/postal services
  ),
  localities = "N3[26]"                     # Pernambuco
) |>
  mutate(
    value  = parse_ibge_value(value),
    period = period_to_monthly(period)
  ) |>
  select(period, classification_11046, locality_name, value)
pms_transport |>
  ggplot(aes(period, value, color = classification_11046)) +
  geom_line() +
  geom_point() +
  labs(
    title = "PMS — Index numbers (2022 = 100)",
    subtitle = "Transportation, storage and postal services (Pernambuco)",
    x = NULL, y = "Index (2022 = 100)", color = NULL
  ) +
  theme_minimal() +
  theme(legend.position = "bottom")
plot of chunk unnamed-chunk-12
plot of chunk unnamed-chunk-12

4) PNAD Contínua (5434) — Accommodation and food services

The Continuous PNAD aggregate 5434 provides quarterly employment data (persons aged 14+ employed) by activity group.

meta_5434 <- ibge_metadata(5434)
unnest(meta_5434$classifications, categories)
#> # A tibble: 13 × 6
#>    id    name             category_id category_name category_unit category_level
#>    <chr> <chr>            <chr>       <chr>         <chr>         <chr>         
#>  1 888   Grupamento de a… 47946       Total         <NA>          0             
#>  2 888   Grupamento de a… 47947       Agricultura,… <NA>          1             
#>  3 888   Grupamento de a… 47948       Indústria ge… <NA>          1             
#>  4 888   Grupamento de a… 60031       Indústria de… <NA>          2             
#>  5 888   Grupamento de a… 47949       Construção    <NA>          1             
#>  6 888   Grupamento de a… 47950       Comércio, re… <NA>          1             
#>  7 888   Grupamento de a… 56622       Transporte, … <NA>          1             
#>  8 888   Grupamento de a… 56623       Alojamento e… <NA>          1             
#>  9 888   Grupamento de a… 56624       Informação, … <NA>          1             
#> 10 888   Grupamento de a… 60032       Administraçã… <NA>          1             
#> 11 888   Grupamento de a… 56627       Outros servi… <NA>          1             
#> 12 888   Grupamento de a… 56628       Serviços dom… <NA>          1             
#> 13 888   Grupamento de a… 60033       Atividades m… <NA>          1
meta_5434$variables
#> # A tibble: 4 × 3
#>   id    name                                                               unit 
#>   <chr> <chr>                                                              <chr>
#> 1 4090  Pessoas de 14 anos ou mais de idade ocupadas na semana de referên… Mil …
#> 2 4091  Coeficiente de variação - Pessoas de 14 anos ou mais de idade ocu… %    
#> 3 4108  Distribuição percentual das pessoas de 14 anos ou mais de idade o… %    
#> 4 4109  Coeficiente de variação - Distribuição percentual das pessoas de … %
pnad_accommodation <- ibge_variables(
  aggregate = 5434,
  variable = 4090,                          # Employed persons (thousands)
  periods = -12,                            # Last 12 quarters
  classification = list("888" = "56623"),   # Accommodation and food services
  localities = "N3[26]"                     # Pernambuco
) |>
  mutate(
    value  = parse_ibge_value(value),
    period = period_to_quarterly(period)
  ) |>
  select(period, classification_888, locality_name, value)
pnad_accommodation |>
  ggplot(aes(period, value)) +
  geom_line() +
  geom_point() +
  labs(
    title = "PNAD Contínua — Employed persons (14+)",
    subtitle = "Accommodation and food services (Pernambuco, thousands)",
    x = NULL, y = "Employed (thousands)"
  ) +
  theme_minimal()
plot of chunk unnamed-chunk-15
plot of chunk unnamed-chunk-15

5) PMS (8693) — Professional and administrative services

Same aggregate as section 3, switching only the activity category in classification 12355:

pms_professional <- ibge_variables(
  aggregate = 8693,
  variable = 7167,
  periods = -12,
  classification = list(
    "11046" = "all",
    "12355" = "31399"                       # Professional/administrative services
  ),
  localities = "N3[26]"
) |>
  mutate(
    value  = parse_ibge_value(value),
    period = period_to_monthly(period)
  ) |>
  select(period, classification_11046, locality_name, value)
pms_professional |>
  ggplot(aes(period, value, color = classification_11046)) +
  geom_line() +
  geom_point() +
  labs(
    title = "PMS — Index numbers (2022 = 100)",
    subtitle = "Professional and administrative services (Pernambuco)",
    x = NULL, y = "Index (2022 = 100)", color = NULL
  ) +
  theme_minimal() +
  theme(legend.position = "bottom")
plot of chunk unnamed-chunk-17
plot of chunk unnamed-chunk-17

6) PNAD Contínua (5434) — Domestic services

pnad_domestic <- ibge_variables(
  aggregate = 5434,
  variable = 4090,
  periods = -12,
  classification = list("888" = "56628"),   # Domestic services
  localities = "N3[26]"
) |>
  mutate(
    value  = parse_ibge_value(value),
    period = period_to_quarterly(period)
  ) |>
  select(period, classification_888, locality_name, value)
pnad_domestic |>
  ggplot(aes(period, value)) +
  geom_line() +
  geom_point() +
  labs(
    title = "PNAD Contínua — Employed persons (14+)",
    subtitle = "Domestic services (Pernambuco, thousands)",
    x = NULL, y = "Employed (thousands)"
  ) +
  theme_minimal()
plot of chunk unnamed-chunk-19
plot of chunk unnamed-chunk-19

7) PIM-PF (8888) — Industrial production (selected CNAE sectors)

The PIM-PF (Monthly Industrial Survey — Physical Production) aggregate 8888 covers manufacturing output. Classification 544 filters by industrial activity (CNAE sections).

meta_8888 <- ibge_metadata(8888)
unnest(meta_8888$classifications, categories)
#> # A tibble: 27 × 6
#>    id    name             category_id category_name category_unit category_level
#>    <chr> <chr>            <chr>       <chr>         <chr>         <chr>         
#>  1 544   Seções e ativid… 129314      1 Indústria … <NA>          0             
#>  2 544   Seções e ativid… 129315      2 Indústrias… <NA>          0             
#>  3 544   Seções e ativid… 129316      3 Indústrias… <NA>          0             
#>  4 544   Seções e ativid… 129317      3.10 Fabrica… <NA>          0             
#>  5 544   Seções e ativid… 129318      3.11 Fabrica… <NA>          0             
#>  6 544   Seções e ativid… 129319      3.12 Fabrica… <NA>          0             
#>  7 544   Seções e ativid… 129320      3.13 Fabrica… <NA>          0             
#>  8 544   Seções e ativid… 129321      3.14 Confecç… <NA>          0             
#>  9 544   Seções e ativid… 129322      3.15 Prepara… <NA>          0             
#> 10 544   Seções e ativid… 129323      3.16 Fabrica… <NA>          0             
#> # ℹ 17 more rows
meta_8888$variables
#> # A tibble: 6 × 3
#>   id    name                                                               unit 
#>   <chr> <chr>                                                              <chr>
#> 1 12606 PIMPF - Número-índice (2022=100)                                   Núme…
#> 2 12607 PIMPF - Número-índice com ajuste sazonal (2022=100)                Núme…
#> 3 11601 PIMPF - Variação mês/mês imediatamente anterior, com ajuste sazon… %    
#> 4 11602 PIMPF - Variação mês/mesmo mês do ano anterior (M/M-12)            %    
#> 5 11603 PIMPF - Variação acumulada no ano (em relação ao mesmo período do… %    
#> 6 11604 PIMPF - Variação acumulada em 12 meses (em relação ao período ant… %
pim_selected <- ibge_variables(
  aggregate = 8888,
  variable = 12606,                         # Index number (2022 = 100)
  periods = -12,
  classification = list(
    "544" = c(129318, 129338)               # Beverages; Motor vehicles
  ),
  localities = "N3[26]"
) |>
  mutate(
    value  = parse_ibge_value(value),
    period = period_to_monthly(period)
  ) |>
  select(period, classification_544, locality_name, value)
pim_selected |>
  ggplot(aes(period, value, color = classification_544)) +
  geom_line() +
  geom_point() +
  labs(
    title = "PIM-PF — Index numbers (2022 = 100)",
    subtitle = "Beverages and Motor vehicles (Pernambuco)",
    x = NULL, y = "Index (2022 = 100)", color = NULL
  ) +
  theme_minimal() +
  theme(legend.position = "bottom")
plot of chunk unnamed-chunk-22
plot of chunk unnamed-chunk-22

8) Construction (8886) — Typical construction inputs

meta_8886 <- ibge_metadata(8886)
meta_8886$variables
#> # A tibble: 4 × 3
#>   id    name                                                               unit 
#>   <chr> <chr>                                                              <chr>
#> 1 12606 PIMPF - Número-índice (2022=100)                                   Núme…
#> 2 11602 PIMPF - Variação mês/mesmo mês do ano anterior (M/M-12)            %    
#> 3 11603 PIMPF - Variação acumulada no ano (em relação ao mesmo período do… %    
#> 4 11604 PIMPF - Variação acumulada em 12 meses (em relação ao período ant… %
construction <- ibge_variables(
  aggregate = 8886,
  variable = 12606,                         # Index number (2022 = 100)
  periods = -12,
  localities = "N1"                         # Brazil
) |>
  mutate(
    value  = parse_ibge_value(value),
    period = period_to_monthly(period)
  ) |>
  select(period, locality_name, value)
construction |>
  ggplot(aes(period, value)) +
  geom_line() +
  geom_point() +
  labs(
    title = "Construction — Typical inputs (physical production)",
    subtitle = "Brazil, index number (2022 = 100)",
    x = NULL, y = "Index (2022 = 100)"
  ) +
  theme_minimal()
plot of chunk unnamed-chunk-25
plot of chunk unnamed-chunk-25

9) PMC (8884 / 8757 / 8880) — Retail trade indices

The Monthly Retail Trade Survey (PMC) publishes volume and revenue indices across different retail segments. The three aggregates below follow the same pattern — classification 11046 selects the index type (volume vs nominal revenue).

9.1 Vehicles, motorcycles, parts and accessories (8884)

meta_8884 <- ibge_metadata(8884)
unnest(meta_8884$classifications, categories)
#> # A tibble: 2 × 6
#>   id    name            category_id category_name   category_unit category_level
#>   <chr> <chr>           <chr>       <chr>           <chr>         <chr>         
#> 1 11046 Tipos de índice 56737       Índice de rece… <NA>          0             
#> 2 11046 Tipos de índice 56738       Índice de volu… <NA>          0
meta_8884$variables
#> # A tibble: 6 × 3
#>   id    name                                                               unit 
#>   <chr> <chr>                                                              <chr>
#> 1 7169  PMC - Número-índice (2022=100)                                     Núme…
#> 2 7170  PMC - Número-índice com ajuste sazonal (2022=100)                  Núme…
#> 3 11708 PMC - Variação mês/mês imediatamente anterior, com ajuste sazonal… %    
#> 4 11709 PMC - Variação mês/mesmo mês do ano anterior (M/M-12)              %    
#> 5 11710 PMC - Variação acumulada no ano (em relação ao mesmo período do a… %    
#> 6 11711 PMC - Variação acumulada em 12 meses (em relação ao período anter… %
pmc_vehicles <- ibge_variables(
  aggregate = 8884,
  variable = 7169,                          # Index number (2022 = 100)
  periods = -12,
  classification = list("11046" = 56738),   # Volume index
  localities = "N3[26]"
) |>
  mutate(
    value  = parse_ibge_value(value),
    period = period_to_monthly(period)
  ) |>
  select(period, classification_11046, locality_name, value)
pmc_vehicles |>
  ggplot(aes(period, value)) +
  geom_line() +
  geom_point() +
  labs(
    title = "PMC — Sales volume index (2022 = 100)",
    subtitle = "Vehicles, motorcycles, parts and accessories (Pernambuco)",
    x = NULL, y = "Index (2022 = 100)"
  ) +
  theme_minimal()
plot of chunk unnamed-chunk-28
plot of chunk unnamed-chunk-28

9.2 Construction materials (8757)

pmc_construction <- ibge_variables(
  aggregate = 8757,
  variable = 7169,
  periods = -12,
  classification = list("11046" = 56732),   # Volume — construction materials
  localities = "N3[26]"
) |>
  mutate(
    value  = parse_ibge_value(value),
    period = period_to_monthly(period)
  ) |>
  select(period, classification_11046, locality_name, value)
pmc_construction |>
  ggplot(aes(period, value)) +
  geom_line() +
  geom_point() +
  labs(
    title = "PMC — Sales volume index (2022 = 100)",
    subtitle = "Construction materials (Pernambuco)",
    x = NULL, y = "Index (2022 = 100)"
  ) +
  theme_minimal()
plot of chunk unnamed-chunk-30
plot of chunk unnamed-chunk-30

9.3 Retail trade (8880)

pmc_retail <- ibge_variables(
  aggregate = 8880,
  variable = 7169,
  periods = -12,
  classification = list("11046" = 56734),   # Volume — retail trade
  localities = "N3[26]"
) |>
  mutate(
    value  = parse_ibge_value(value),
    period = period_to_monthly(period)
  ) |>
  select(period, classification_11046, locality_name, value)
pmc_retail |>
  ggplot(aes(period, value)) +
  geom_line() +
  geom_point() +
  labs(
    title = "PMC — Sales volume index (2022 = 100)",
    subtitle = "Retail trade (Pernambuco)",
    x = NULL, y = "Index (2022 = 100)"
  ) +
  theme_minimal()
plot of chunk unnamed-chunk-32
plot of chunk unnamed-chunk-32

Next steps

  1. Save the series in a standardised format (e.g. arrow::write_parquet() or a database) for reproducible dashboards.
  2. Build a state GDP tracking dashboard with normalisation (base 100), smoothing (moving averages), and variation indicators (month-over-month, year-over-year).
  3. Wrap each block (IPCA, PMS, PNAD, PIM-PF, PMC) into a dedicated function to reduce repetition in production code.

These binaries (installable software) and packages are in development.
They may not be fully stable and should be used with caution. We make no claims about them.