WEEE Forum Fast-Tech Consumer Study

Survey design, fieldwork, sample composition, weighting, data processing and ethical safeguards.

Authors
Affiliation

Dimitri Naczaj, Ph.D.

Éric Bonetto, Ph.D.

Published

4 September 2026

Show R code
source("R/fast-tech-shared.R")

1 Study design

The WEEE Forum and its participating members commissioned a cross-sectional survey of adults living in 12 European countries. The study examines the purchase, ownership, use and end-of-life treatment of fast-tech devices, as well as purchasing intentions, perceptions, social norms, willingness to pay for durability and support for regulation.

The survey is descriptive and observational. Population calibration improves the correspondence between the achieved sample and selected demographic margins, but it does not turn associations into causal effects or fully remove online-panel coverage and self-selection bias.

1.1 Definition of fast tech

Fast tech does not yet have a widely accepted operational definition. To avoid priming respondents or introducing the evaluative connotations associated with fast fashion, the questionnaire did not use the term fast tech. Instead, we referred to small and inexpensive electronic devices, with an indicative maximum cost of €10 (€15 for Switzerland) or €20. This neutral description captures the physical and market characteristics of the products without presupposing their quality, lifespan, accessibility or environmental impact. We made sure it could be translated consistently across the participating countries.

For the purposes of this study, the devices were grouped into four categories:

  1. Charging and lighting devices under €10, described as: “chargers, adapters, charging cables (USB-A, USB-C, lightning, micro-USB…), LED strips and light bulbs, clip-on and small desk lamps, decorative and garden lights…”
  2. High-tech devices under €20, described as: “Bluetooth or wired audio devices (earphones/headphones, speakers…), power banks, wearables and fitness trackers (like smart bands and smartwatches), PC accessories (USB drives or hubs, mice, keyboards, webcams…), game controllers…”
  3. Gadgets and lifestyle items under €20, described as: “mini fans and diffusers, desktop gadgets, electronic toys (handheld consoles, fidget toys, RC cars…), cooking appliances (milk frother, mini blender, cookers…), body and skin devices (mini massager, travel razor or electric toothbrush…), home devices (alarms, cameras, smart sensors, bug zapper), pet gadgets (laser toys, auto feeder or water fountain…)”
  4. Disposable single-use e-vapes.

The first three categories form the core definition used in the analyses of purchasing and buyer status. Disposable e-vapes were treated separately, since their use and purchasing context differ from those of the other devices. They were included in the questions on household ownership and quantities disposed of, but excluded from the principal measures of purchasing behaviour and from the buyer/non-buyer classification.

2 Study material

2.1 Questionnaire

The definitive questionnaire is available as a PDF. The following section provides a summary.

Household characteristics

Q1. How old are you? Numeric response from 18; younger respondents were terminated.

Q2. Including yourself, how many people live in your household? Numeric response.

Q2a. How many of them are under 18 years old? Numeric response.

Buying and ownership

Q3. How many of the following items did you personally buy over the last 12 months? Charging and lighting devices; high-tech devices; gadgets and lifestyle items. Response bands: none, 1, 2–5, 6–9, 10–19, 20 or more.

Q4. How many of the following items are currently in your household, regardless of who bought or owns them? The three categories above plus disposable single-use e-vapes. The same quantity bands were used.

Q5. Have you ever bought small and inexpensive electronic devices, excluding e-vapes? Yes, quite often; yes, occasionally; yes, once; no, never.

Q6. Why have you never bought a small and inexpensive electronic device? Multiple answers covering lack of need, lack of awareness, quality/durability concerns, preference for higher-quality alternatives, insufficient societal impact, someone else purchasing devices, uncertainty and other reasons.

Q7. How often do you come across small and inexpensive electronic devices? Every day; at least weekly; at least monthly; a few times a year; less often or never.

Q8. For selected fast-tech categories, did you intend to buy the item? Intended purchase; not intended.

Q9. Why did you buy the item? Multiple answers covering work or everyday use, temporary replacement, a newer version, a spare, an unneeded impulse purchase, a gift, lack of another choice and other reasons.

Q10. What generally makes you buy small and inexpensive electronic devices rather than more expensive alternatives? Multiple answers covering affordability, immediate availability, accessibility, design, recommendations, advertising, curiosity and uncertainty.

Q11. Where do you usually get these devices? Multiple answers covering brand websites, online stores and marketplaces, discount or second-hand stores, airports and stations, social media, personal contacts and other channels.

Use and end of life

Q12. Among the devices bought during the last 12 months, how many are still personally used today? None, 1, 2–5, 6–9, 10–19, 20 or more.

Q13. What is the shortest period for which you have used one of these devices? Discarding immediately; single use; less than a week; less than a month; one to six months; six to twelve months; twelve months or more; do not know or remember.

Q14. Over the last 12 months, how many devices did you personally dispose of? Charging and lighting devices, high-tech, gadgets and lifestyle items, and disposable e-vapes; quantity bands from none to 20 or more.

Q15. What are the main reasons you stopped using these devices? Multiple answers covering not working, intended single use, obsolescence, quality, damage, becoming outdated, lack of need, uncertainty and other reasons.

Q16. What have you done with the devices you stopped using? Multiple answers covering keeping them, household waste, plastic-waste sorting, recycling centres, in-store collection, giving away or donating, selling, uncertainty and other actions.

Q17. Why did you choose these end-of-life solutions? Multiple answers covering not thinking about it, convenience, availability, knowledge, perceived responsibility, resale value, repair difficulty, others’ recommendations, uncertainty and other motivations.

Perception and willingness

Q18. Overall, how satisfied were you with the devices you used? Very dissatisfied to very satisfied.

Q19. Would you have been willing to pay more for similar items that could be used over a longer period? No; yes for some; yes for most; yes for all.

Q20. If you had to replace a broken device, what would you choose? The same inexpensive model; another small inexpensive device; a more expensive one; repair; other.

Q21a. Globally, did the devices have a shorter, similar or greater lifespan than expected?

Q21b. Were they of lower, similar or higher quality than expected?

Q22a. Compared with more expensive alternatives, were they less, similarly or more harmful to the environment?

Q22b. Compared with more expensive alternatives, did they have a shorter, similar or greater lifespan?

Behaviour

Q23a. Regarding buying small and inexpensive electronic devices, how favourable are you? Completely unfavourable to completely favourable.

Q23b. People important to you would… Completely disapprove to completely approve.

Q24. Compared with a year ago, how many people buy small and inexpensive electronic devices? Far fewer; fewer; the same number; more; far more.

Intention, policy and awareness

Q25. Over the next 12 months, do you intend to buy more, fewer or the same number of small and inexpensive electronic devices? Much more; more; the same; less; much less; intend to stop.

Q26a. Consumers should buy fewer small and inexpensive electronic devices. Five-point agreement scale.

Q26b. Governments should more strictly regulate the sale of small and inexpensive electronic devices. Five-point agreement scale.

Q27. Did you know that online platforms selling electronic devices are legally required to contribute financially to electronic-waste collection and recycling? Yes; no; had heard of it but did not know the details.

Q28. Before taking this questionnaire, were you aware that these devices contain electronic parts? Yes; no.

Demographics

Q29. How should you define yourself? Male; female; non-binary; other; prefer not to say.

Q30. What is your highest diploma? From no formal education to master’s degree or equivalent; prefer not to say.

Q31. What is your employment status? Unemployed; employed; self-employed; student; home-maker or caregiver; retired; other; prefer not to say.

Q32. What is your household annual income? Country-specific bands in local currency; prefer not to say.

Q33. Where do you live? Large city; suburb; small or medium-sized city; rural area or village; other; prefer not to say.

2.2 Questionnaire translation

The questionnaire has been built in English, then translated in 13 languages. The translation table is available as an Excel file.

2.3 Dataset

The anonymised dataset is available to participating members upon request to the authors or WEEE Forum staff.

3 Sample Overview

The sample covers 12 countries, with 10,245 participants. This section describes the achieved sample without applying analytical weights.

3.1 Respondents by country

The target sample size was reached for every participating country.

Show R code
country_counts <- df |>
  count(Country, name = "n") |>
  arrange(desc(n)) |>
  mutate(Share = n / sum(n))

country_gender_tooltips <- df |>
  mutate(
    Gender = recode(Gender, `98` = "No answer"),
    Gender = factor(
      Gender,
      levels = c(
        "Female",
        "Male",
        "Non-binary",
        "Prefer not to say",
        "No answer"
      )
    )
  ) |>
  filter(Gender %in% c("Female", "Male")) |>
  group_by(Country, Gender, .drop = FALSE) |>
  summarise(
    gender_n = n(),
    .groups = "drop_last"
  ) |>
  mutate(gender_pct = gender_n / sum(gender_n)) |>
  filter(gender_n > 0) |>
  arrange(Country, Gender) |>
  summarise(
    gender_tooltip = paste0(
      Gender,
      ": ",
      percent(gender_pct, accuracy = 0.1),
      " (n = ",
      comma(gender_n),
      ")",
      collapse = "\n"
    ),
    .groups = "drop"
  )

country_age_tooltips <- df |>
  group_by(Country) |>
  summarise(
    mean_age = mean(Age, na.rm = TRUE),
    .groups = "drop"
  )

country_counts |>
  gt() |>
  cols_label(Country = "Country", n = "N", Share = "%") |>
  fmt_percent(columns = Share, decimals = 1) |>
  grand_summary_rows(
    columns = n,
    fns = list(Total = ~sum(.)),
    fmt = ~ fmt_integer(.)
  ) |>
  gt_bellegarde()
Table 1: Number and share of respondents per country
Country N %
France 1505 14.7%
Belgium 1503 14.7%
Romania 1205 11.8%
Poland 1009 9.8%
Ireland 1003 9.8%
Switzerland 1000 9.8%
Norway 505 4.9%
Greece 504 4.9%
Netherlands 504 4.9%
Portugal 503 4.9%
Spain 503 4.9%
UK 501 4.9%
Total — 10,245 —
Show R code
p_map <- map_data("world") |>
  filter(region %in% europe_context) |>
  left_join(
    country_counts |>
      left_join(country_gender_tooltips, by = "Country") |>
      left_join(country_age_tooltips, by = "Country") |>
      mutate(region = Country) |>
      select(
        region,
        n,
        gender_tooltip,
        mean_age
      ),
    by = "region"
  ) |>
  mutate(
    tooltip = if_else(
      !is.na(n),
      paste0(
        region,
        "\nN = ",
        comma(n),
        "\n\nGender\n",
        gender_tooltip,
        "\n\nMean age: ",
        number(mean_age, accuracy = 0.1),
        " years"
      ),
      NA_character_
    )
  ) |>
  ggplot(aes(x = long, y = lat, group = group, fill = n,
             tooltip = tooltip, data_id = region)) +
  geom_polygon_interactive(
    colour = bg_surface,
    linewidth = bg_lw_hairline
  ) +
  coord_map("lambert", lat0 = 45, lat1 = 60,
            xlim = c(-12, 35), ylim = c(34, 72)) +
  scale_fill_bg_c(
    palette = "seq",
    name = "N",
    limits = c(0, 1510),
    breaks = c(0, 500, 1000, 1500),
    labels = label_comma(),
  ) +
  labs(x = NULL, y = NULL) +
  theme(
    axis.text = element_blank(),
    panel.grid = element_blank(),
    legend.position = "top"
  )

girafe(
  ggobj = p_map,
  font_set = gdtools::font_set(),
  width_svg = bg_fig_width_body,
  height_svg = bg_fig_height,
  options = list(
    opts_hover(css = paste0("fill:", bg_accent_50, ";")),
    opts_toolbar(saveaspng = FALSE),
    opts_sizing(rescale = TRUE)
  )
)
Figure 1: Geographic distribution of respondents

3.2 Demographics

3.2.1 Age and gender

Q1. How old are you?

Q29. How would you define yourself?

The survey included respondents across a broad age range, from 18 to 89 years old.

Show R code
df |>
  filter(!is.na(Age)) |>
  ggplot(aes(x = Age)) +
  geom_density(
    fill = bg_accent,
    colour = bg_success,
    alpha = bg_alpha_mute,
    linewidth = bg_lw_line
  ) +
  scale_x_continuous(breaks = seq(18, 100, by = 10)) +
  labs(x = "Age", y = "Density")
Figure 2: Age group distribution
Show R code
gender_summary <- df |>
  mutate(Gender = na_if(Gender, "98")) |>
  filter(!is.na(Gender)) |>
  count(Gender, name = "n") |>
  mutate(pct = n / sum(n))

gender_pct <- setNames(gender_summary$pct, gender_summary$Gender)

Women account for 50.3% of the observed sample and men for 48.7%. This corresponds to 5,134 women and 4,977 men.

Show R code
gender_summary |>
  ggplot(aes(x = reorder(Gender, pct), y = pct)) +
  geom_col(width = bg_bar_width, fill = bg_accent) +
  geom_text(aes(label = percent(pct, accuracy = 0.1)), hjust = -0.2, size = bg_size_label / .pt) +
  scale_y_continuous(labels = percent_format(), expand = expansion(mult = c(0, 0.1))) +
  coord_flip() +
  labs(x = NULL, y = NULL)
Figure 3: Gender distribution

3.2.2 Employment

Show R code
employment_summary <- df |>
  filter(
    !is.na(Employment),
    Employment != "Prefer not to say"
  ) |>
  count(Employment, name = "n") |>
  mutate(pct = n / sum(n))

employment_percent_by_status <- setNames(
  employment_summary$pct,
  employment_summary$Employment
)

Q31. What’s your employment status?

60.9% of respondents are employed or self-employed, 20.9% are retired and 7.2% are unemployed.

Show R code
employment_summary |>
  mutate(
    highlight = pct == max(pct)
  ) |>
  ggplot(
    aes(
      x = reorder(Employment, pct),
      y = pct,
      fill = highlight
    )
  ) +
  geom_col(width = bg_bar_width) +
  geom_text(
    aes(label = percent(pct, accuracy = 0.1)),
    hjust = -0.2,
    size = bg_size_label / .pt
  ) +
  scale_fill_manual(
    values = c(
      "TRUE" = bg_accent,
      "FALSE" = bg_accent_50
    ),
    guide = "none"
  ) +
  scale_y_continuous(
    labels = percent_format(),
    expand = expansion(mult = c(0, 0.1))
  ) +
  coord_flip() +
  labs(x = NULL, y = NULL)
Figure 4: Employment status

3.2.3 Education

Q30. What is your highest diploma?

Secondary school or high school was the most frequently reported highest education level (35.4%), followed by a bachelor’s degree or equivalent (28.8%). Then, 17.7% reported a master’s or doctoral degree, or equivalent qualification.

Show R code
education_levels <- c(
  "No formal education / Primary school",
  "Secondary school / High school",
  "College / Undergraduate",
  "Bachelor or equivalent",
  "Master or equivalent / Doctorate, Ph.D. or equivalent",
  "Prefer not to say"
)

df |>
  filter(!is.na(Education)) |>
  count(Education, name = "n") |>
  mutate(
    pct = n / sum(n),
    # coord_flip() displays the last factor level at the top.
    Education = factor(
      Education,
      levels = rev(education_levels)
    ),
     response_type = if_else(
      Education == "Prefer not to say",
      "Prefer not to say",
      "Substantive response"
    )
  ) |>
  ggplot(
    aes(
      x = Education,
      y = pct,
      fill = response_type
    )
  ) +
  geom_col(width = bg_bar_width) +
  geom_text(
    aes(label = percent(pct, accuracy = 0.1)),
    hjust = -0.2,
    size = bg_size_label / .pt
  ) +
  scale_fill_manual(
    values = c(
      "Substantive response" = bg_accent,
      "Prefer not to say" = bg_ink_32
    ),
    guide = "none"
  ) +
  scale_x_discrete(
    labels = \(x) str_wrap(x, width = 35)
  ) +
  scale_y_continuous(
    labels = percent_format(),
    expand = expansion(mult = c(0, 0.1))
  ) +
  coord_flip() +
  labs(x = NULL, y = NULL)
Figure 5: Highest education level

3.2.4 Household size

Q2. Including yourself, how many people live in your household?

Q2a. How many of them are under 18 years old?

Show R code
df |>
  filter(!is.na(Nb_household)) |>
  mutate(hh_group = case_when(
    Nb_household == 1 ~ "1",
    Nb_household == 2 ~ "2",
    Nb_household == 3 ~ "3",
    Nb_household == 4 ~ "4",
    Nb_household >= 5 ~ "5+"
  )) |>
  group_by(hh_group) |>
  summarise(
    n = n(),
    .groups = "drop"
  ) |>
  mutate(pct = n / sum(n)) |>
  ggplot(aes(x = hh_group, y = pct)) +
  geom_col(width = bg_bar_width, fill = bg_accent) +
  geom_text(aes(label = percent(pct, accuracy = 0.1)), vjust = -0.4, size = bg_size_label / .pt) +
  scale_y_continuous(labels = percent_format(), expand = expansion(mult = c(0, 0.08))) +
  labs(x = "Household size", y = NULL)
Figure 6: Number of people per household
Show R code
df |>
  filter(!is.na(Nb_household_under18)) |>
  mutate(has_children = if_else(
    Nb_household_under18 > 0,
    "With children under 18",
    "No children under 18"
  )) |>
  group_by(has_children) |>
  summarise(
    n = n(),
    .groups = "drop"
  ) |>
  mutate(pct = percent(n / sum(n), accuracy = 0.1)) |>
  select(has_children, n, pct) |>
  gt() |>
  cols_label(has_children = "", n = "N", pct = "%") |>
  gt_bellegarde()
Table 2: Households with children under 18
N %
No children under 18 4546 54.2%
With children under 18 3836 45.8%

3.2.5 Household income

Show R code
income_data <- df |>
  transmute(
    Country,
    Income = coalesce(
      Income_Norway,
      Income_Romania,
      Income_Poland,
      Income_Switzerland,
      Income_UK,
      Income_Euro
    )
  )

income_ridge_data <- income_data |>
  filter(
    !is.na(Income),
    Income != "Prefer not to say"
  ) |>
  mutate(
    income_lower = income_lower_bound(
      Income
    )
  ) |>
  group_by(Country) |>
  mutate(
    bracket_position = assign_income_bracket_position(
      Country,
      income_lower
    ),
    n_brackets = n_distinct(
      income_lower
    ),
    income_eur_equivalent = case_when(
      Country == "Switzerland" &
        bracket_position == n_brackets ~ 135000,
      TRUE ~ 5000 +
        (bracket_position - 1) * 10000
    )
  ) |>
  ungroup() |>
  mutate(
    Country = fct_reorder(
      Country,
      income_eur_equivalent,
      .fun = median,
      .desc = TRUE
    )
  )

pct_income_prefer_not <- mean(
  income_data$Income == "Prefer not to say",
  na.rm = TRUE
)

Q32. What’s your household annual income?

Household income was collected using country-specific ranges expressed in local currencies. These ranges were designed as approximate equivalents of the same €10,000 income bands, allowing their distributions to be displayed on a shared euro-equivalent scale. Overall, 7.2% preferred not to report their household income.

Note: Each income bracket represents an approximate €10,000 interval. Because of the conversion applied to the Swiss response scale, Switzerland had one fewer bracket. The apparent gap between €120,000 and €130,000 is therefore an artefact of harmonisation, and the scale should be read as continuous across that interval.

Show R code
income_ridge_data |>
  ggplot(aes(
    x = income_eur_equivalent,
    y = Country,
    group = Country,
    fill = Country
  )) +
  ggridges::geom_density_ridges(
    stat = "binline",
    binwidth = 10000,
    boundary = 0,
    scale = 0.92,
    alpha = 0.6,
    colour = "#000000",
    linewidth = bg_lw_hairline
  ) +
  scale_fill_hue(
    guide = "none"
  ) +
  scale_x_continuous(
    breaks = seq(0, 140000, by = 20000),
    labels = function(x) {
      if_else(
        x == 0,
        "€0",
        paste0("€", x / 1000, "k")
      )
    },
    limits = c(0, 140000),
    expand = expansion(add = c(2500, 2500))
  ) +
  scale_y_discrete(
    expand = expansion(add = c(0.25, 0.75))
  ) +
  coord_cartesian(
    clip = "off"
  ) +
  labs(
    x = "Approximate annual household income equivalent (€)",
    y = NULL
  ) +
  theme(
    panel.grid.major.y = element_blank(),
    panel.grid.minor = element_blank(),
    legend.position = "none"
  )
Figure 7: Distribution of household income responses, by country and approximate euro-equivalent bracket

3.2.6 Residential environment

Show R code
location_levels <- c(
  "Large city",
  "Suburb of a large city",
  "Small or medium sized city",
  "Rural area or village",
  "Other",
  "Prefer not to say"
)

location_summary <- df |>
  filter(!is.na(Location)) |>
  count(Response = Location, name = "n") |>
  mutate(
    Response = factor(Response, levels = location_levels),
    pct = n / sum(n)
  ) |>
  arrange(Response)

location_pct <- setNames(
  location_summary$pct,
  as.character(location_summary$Response)
)

Q33. Where do you live?

The sample includes respondents from a range of residential environments. Large cities account for 31.3% of respondents and small or medium-sized cities for 28.6%. A further 16.1% live in the suburbs of a large city, while 23.3% live in a rural area or village.

Show R code
location_summary |>
  mutate(
    response_type = if_else(
      Response %in% c(
        "Other",
        "Prefer not to say"
      ),
      "Non-substantive response",
      "Residential environment"
    )
  ) |>
  ggplot(aes(
    x = pct,
    y = fct_rev(Response),
    fill = response_type
  )) +
  geom_col(width = bg_bar_width) +
  geom_text(
    aes(label = percent(pct, accuracy = 0.1)),
    hjust = -0.15,
    size = bg_size_label / .pt
  ) +
  scale_fill_manual(
    values = c(
      "Residential environment" = bg_accent,
      "Non-substantive response" = bg_ink_32
    ),
    guide = "none"
  ) +
  scale_x_continuous(
    labels = percent_format(),
    expand = expansion(mult = c(0, 0.16))
  ) +
  scale_y_discrete(
    labels = \(x) str_wrap(x, width = 35)
  ) +
  labs(
    x = "% of respondents",
    y = NULL
  )
Figure 8: Residential environment of respondents

4 Weighting

The sample overview reports the respondents exactly as observed. The analyses in this report use post-stratification weights so that pooled estimates reflect the combined population aged 18–99 of the 12 participating countries, while aligning age and gender within each country. The figures below show this adjustment.

Population margins were taken from the United Nations World Population Prospects 2024, medium projection for 1 January 2026 (United Nations, Department of Economic and Social Affairs, Population Division, 2024). Age and gender distributions were calculated for the population aged 18–99 in each participating country.

Show R code
weighting_age_data <- bind_rows(
  df |>
    transmute(
      Age,
      Distribution = "Observed sample",
      curve_weight = 1
    ),
  df |>
    transmute(
      Age,
      Distribution = "Population-weighted",
      curve_weight = analysis_weight
    )
) |>
  filter(!is.na(Age)) |>
  mutate(
    Distribution = factor(
      Distribution,
      levels = c(
        "Observed sample",
        "Population-weighted"
      )
    )
  )

sample_mean_age <- mean(df$Age, na.rm = TRUE)
weighted_mean_age <- weighted_mean_safe(
  df$Age,
  df$analysis_weight
)

weighting_gender_summary <- df |>
  mutate(
    Gender = recode(Gender, `98` = "No answer")
  ) |>
  filter(!is.na(Gender)) |>
  group_by(Gender) |>
  summarise(
    n = n(),
    weighted_n = sum(analysis_weight),
    .groups = "drop"
  ) |>
  transmute(
    Gender,
    `Observed sample` = n / sum(n),
    `Population-weighted` = weighted_n / sum(weighted_n)
  ) |>
  pivot_longer(
    -Gender,
    names_to = "Distribution",
    values_to = "pct"
  ) |>
  mutate(
    Distribution = factor(
      Distribution,
      levels = c(
        "Observed sample",
        "Population-weighted"
      )
    )
  )

The adjustment changes mean age from 47.3 years in the observed sample to 49.2 years after weighting.

Show R code
weighting_age_data |>
  ggplot(aes(
    x = Age,
    weight = curve_weight,
    colour = Distribution,
    fill = Distribution
  )) +
  geom_density(
    alpha = 0.16,
    linewidth = bg_lw_line
  ) +
  scale_colour_manual(
    name = NULL,
    values = c(
      "Observed sample" = bg_ink_54,
      "Population-weighted" = bg_accent
    )
  ) +
  scale_fill_manual(
    name = NULL,
    values = c(
      "Observed sample" = bg_ink_32,
      "Population-weighted" = bg_accent_50
    )
  ) +
  scale_x_continuous(
    breaks = seq(18, 100, by = 10)
  ) +
  labs(
    x = "Age",
    y = "Density"
  ) +
  theme(legend.position = "top")
Figure 9: Observed and population-weighted age distributions
Show R code
weighting_gender_summary |>
  ggplot(aes(
    x = pct,
    y = fct_rev(Gender),
    fill = Distribution
  )) +
  geom_col(
    position = position_dodge(width = 0.72),
    width = 0.64
  ) +
  geom_text(
    aes(label = percent(pct, accuracy = 0.1)),
    position = position_dodge(width = 0.72),
    hjust = -0.15,
    size = bg_size_label / .pt
  ) +
  scale_fill_manual(
    name = NULL,
    values = c(
      "Observed sample" = bg_ink_32,
      "Population-weighted" = bg_accent
    )
  ) +
  scale_x_continuous(
    labels = percent_format(),
    limits = c(0, 0.55),
    expand = expansion(mult = c(0, 0.04))
  ) +
  labs(
    x = "% within each distribution",
    y = NULL
  ) +
  theme(legend.position = "top")
Figure 10: Observed and population-weighted gender distributions

Note: Weighting corrects the sample on observed age, gender and country-population margins. It does not remove possible coverage, panel-selection or response biases on characteristics that were not used for calibration.


5 Data gathering

5.1 Fieldwork

Show R code
completion_time_p99 <- unname(
  quantile(df$qTimeMin, 0.99, na.rm = TRUE)
)

completion_time_plot_data <- df |>
  filter(
    !is.na(qTimeMin),
    qTimeMin <= completion_time_p99
  )

completion_age_breaks <- c(18, 25, 35, 45, 55, 65, Inf)
completion_age_labels <- c(
  "18–24",
  "25–34",
  "35–44",
  "45–54",
  "55–64",
  "65+"
)

completion_time_by_age <- completion_time_plot_data |>
  mutate(
    Age_group = cut(
      Age,
      breaks = completion_age_breaks,
      labels = completion_age_labels,
      right = FALSE
    )
  ) |>
  filter(!is.na(Age_group))

Responses were collected through an online access panel in July 2026, over approximately one month. Country quotas were set in advance, with 1,500 participants in Belgium and France and at least 500 completed interviews in each participating country. Eligibility was restricted to adults aged 18 or over. Questionnaire routing adapted the questions to previous buyers and non-buyers and randomly selected fast-tech categories where indicated.

The questionnaire described an expected completion time of approximately 15 minutes. The observed median was 6.6 minutes; the middle 50% of sessions lasted from 4.6 to 10.1 minutes.

Show R code
completion_time_plot_data |>
  ggplot(aes(x = qTimeMin)) +
  geom_histogram(
    binwidth = 1,
    boundary = 0,
    fill = bg_accent,
    colour = bg_surface,
    linewidth = bg_lw_hairline
  ) +
  geom_vline(
    xintercept = response_time_median,
    colour = bg_ink,
    linewidth = bg_lw_line,
    linetype = "dashed"
  ) +
  annotate(
    "text",
    x = response_time_median,
    y = Inf,
    label = paste0(
      "Median: ",
      number(response_time_median, accuracy = 0.1),
      " min"
    ),
    hjust = -0.1,
    vjust = 1.4,
    size = bg_size_label / .pt
  ) +
  scale_x_continuous(
    breaks = pretty_breaks(8),
    expand = expansion(mult = c(0, 0.02))
  ) +
  labs(
    x = "Completion time (minutes)",
    y = "Respondents"
  )
Figure 11: Questionnaire completion time

Note: The graph excludes only the longest 1% of completion times to improve readability.

Show R code
completion_time_by_age |>
  ggplot(aes(
    x = qTimeMin,
    y = fct_rev(Age_group)
  )) +
  geom_boxplot(
    width = 0.58,
    fill = bg_accent_50,
    colour = bg_accent,
    outlier.alpha = 0.12,
    outlier.size = 0.8,
    linewidth = bg_lw_line
  ) +
  labs(
    x = "Completion time (minutes)",
    y = "Age group"
  )
Figure 12: Questionnaire completion time by age group

6 Data cleaning and transformation

6.1 Eligibility and completion status

The analysis file contains 10,245 qualified completed cases. No respondent in the delivered file is younger than 18, consistent with the questionnaire’s termination rule for minors. Routing-based missing values were preserved as structurally missing rather than recoded as substantive answers.

6.2 Response-quality checks

Online-panel quality control can combine identity verification, fraud detection and survey-taking behaviour (DeSimone et al., 2015; Meade & Craig, 2012). Dynata’s published procedures specifically mention checks for speeding, straight-lining, duplicates and low-effort open-ended responses, alongside broader respondent-level quality scoring (Dynata, 2026). The delivered file contains qualified cases but not the provider’s underlying fraud scores, device movements, keystroke patterns or exclusion log; those upstream decisions cannot therefore be independently reconstructed here.

Show R code
fast_response_threshold <- response_time_median / 3
fast_response_n <- sum(
  df$qTimeMin < fast_response_threshold,
  na.rm = TRUE
)

quality_check_summary <- tibble(
  Check = c(
    "Qualified completion status",
    "Respondent aged under 18",
    "Completion time below one-third of the median",
    "Reconstructable straight-lining flag"
  ),
  Result = c(
    format_count(n_participants),
    format_count(sum(df$Age < 18, na.rm = TRUE)),
    paste0(
      format_count(fast_response_n),
      " below ",
      number(fast_response_threshold, accuracy = 0.1),
      " minutes"
    ),
    "Not available"
  ),
  Treatment = c(
    "Included in the analysis file",
    "None present after the eligibility filter",
    "Flagged for sensitivity review; duration alone was not an automatic exclusion",
    "Relied on provider controls; the questionnaire has no sufficiently long uniform response grid"
  )
)
Show R code
quality_check_summary |>
  gt() |>
  cols_width(
    Check ~ pct(31),
    Result ~ pct(22),
    Treatment ~ pct(47)
  ) |>
  gt_bellegarde()
Table 3: Reproducible response-quality checks in the delivered dataset
Check Result Treatment
Qualified completion status 10,245 Included in the analysis file
Respondent aged under 18 0 None present after the eligibility filter
Completion time below one-third of the median 124 below 2.2 minutes Flagged for sensitivity review; duration alone was not an automatic exclusion
Reconstructable straight-lining flag Not available Relied on provider controls; the questionnaire has no sufficiently long uniform response grid

A completion time below one-third of the sample median is used here as a transparent diagnostic convention, not as proof of a low-quality response. The 124 flagged sessions were retained in the primary analyses because survey duration depends on routing, reading speed and interruptions. Likewise, identical answers across a small number of related attitude questions are not sufficient to diagnose straight-lining: they can represent a coherent opinion.

6.3 Recoding

The original export used long questionnaire labels and included panel-administration fields. The following transformations were applied:

  • Analytical columns were given stable, interpretable names.
  • Response labels and factor orders were standardised.
  • Multiple-response items were converted into selection indicators.
  • Country-specific income bands were mapped to common approximate bracket positions.

The dynamic-norm item was centred from −2 (far fewer people) to +2 (far more people), with 0 representing the same number.

7 Data protection and GDPR

The questionnaire informed participants that their answers would be treated confidentially, analysed in aggregate and processed anonymously for research purposes. Participation was voluntary and continuing to the survey constituted consent under the wording shown to respondents.

The public analysis dataset excludes direct panel identifiers and administrative fields such as respondent UUIDs and record identifiers. Results are reported as aggregates, and low-frequency categories are interpreted cautiously. The restricted internal source remains separate from the downloadable analytical file. Data minimisation, purpose limitation and restricted access should continue to govern storage, sharing and any future linkage.

Note: Removing direct identifiers reduces disclosure risk, but cannot guarantee that the risk of identification is zero. Any public release should therefore retain only the variables necessary for reproducibility and avoid unnecessary geographic or demographic detail.

8 Ethical note

8.2 Bellegarde principles applied to this study

Bellegarde helps organisations understand and change attitudes and behaviour related to the circular economy. Our work is grounded in science but is not intended to remain confined to academic publication. We aim to support collective action and structural improvement through the best available evidence.

The following commitments guided this work:

  1. Scientific rigour. Analytical choices are grounded in reproducible methods, documented assumptions and the strongest evidence available. Uncertainty, measurement limits and the non-causal nature of cross-sectional associations are reported rather than concealed.
  2. Impact orientation. Analyses are organised around concrete WEEE Forum objectives and actionable environmental questions. Recommendations should be measurable, field-tested and evaluated for both intended and unintended effects.
  3. Uncompromising ethics. Integrity, transparency and responsibility guide the choice of questions, methods and interpretations. People are treated with respect, and the work is undertaken in the public interest without imposing behaviour.
  4. Accessibility and accountability. Methods, results and behavioural levers are made as transparent and accessible as confidentiality and data-protection constraints allow.

These principles align with recognised scientific codes of conduct and international good-practice frameworks, including the OECD’s emphasis on research integrity (Organisation for Economic Co-operation and Development, 2022). Changing behaviour is not a matter of intuition: it requires evidence, proportionate methods and responsibility for the consequences of action. This is what we do.

9 Understanding the statistical notation

The reports use a small number of statistical terms. They are explained below in plain language.

9.1 Correlation

A correlation shows whether two measures tend to increase or decrease together. It does not show that one causes the other.

Example: respondents reporting more fast tech purchases also tend to report more devices disposed of.

Notation: Spearman’s ρ = 0.57. The positive value shows that the two measures tend to increase together. A value of 0 would indicate no monotonic association, while values closer to +1 or −1 indicate stronger associations.

Show R code
correlation_example_points |>
  ggplot(aes(
    x = purchased_count,
    y = disposed_count
  )) +
  geom_jitter(
    width = 0.55,
    height = 0.55,
    alpha = 0.14,
    size = 1.2,
    colour = bg_accent
  ) +
  geom_smooth(
    data = correlation_example_plot_data,
    method = "loess",
    formula = y ~ x,
    span = 0.8,
    se = FALSE,
    colour = bg_success,
    linewidth = bg_lw_line
  ) +
  coord_cartesian(
    xlim = c(
      0,
      correlation_example_limits[["purchased"]]
    ),
    ylim = c(
      0,
      correlation_example_limits[["disposed"]]
    )
  ) +
  labs(
    x = "Estimated number purchased",
    y = "Estimated number disposed of"
  )
Figure 13: Example of a positive correlation: estimated fast tech purchases and disposal

Each dot represents one respondent in a random display sample. The green line summarises the trend. The counts are estimates based on the midpoints of the questionnaire’s response bands.

9.2 P-value

A p-value indicates how unusual the observed result would be if there were no association in the population.

Example: a small p-value for age and buying status means that the observed age difference would be difficult to explain by random sampling alone.

Notation: p < .001 means that a result at least this unusual would occur fewer than once in 1,000 samples if the hypothesis we have to explain the result would be false. It is not the probability that the hypothesis is true.

9.3 Corrected p-value

When many associations are tested, p-values are corrected to reduce the risk of highlighting a result coming from chance and not a real effect.

Example: the behavioural models use the Benjamini–Hochberg correction when several potential factors are compared.

Notation: q = .03 is a corrected p-value. A threshold such as q < .05 limits the expected proportion of false discoveries among the results declared significant.

9.4 Interquartile range

The interquartile range (IQR) contains the middle half of the observations, between the 25th and 75th percentiles.

Example: the middle half of questionnaire sessions lasted from 4.6 to 10.1 minutes.

Notation: median = 6.6 min, IQR = 4.6–10.1 min.

9.5 Beta coefficient

A beta coefficient gives the direction and size of an association in a statistical model, while the other factors in that model are held constant.

Example: a positive beta coefficient for buying attitude means that a more favourable attitude is associated with a higher value of the outcome. Its numerical size depends on the outcome scale and the model used.

Notation: β = 0.25 means that a one-unit increase in the predictor is associated with a 0.25-unit increase in the outcome, when the model is linear and the other variables remain constant.

9.6 Confidence interval

A confidence interval shows the range of values that remain reasonably compatible with the data and the statistical model.

Example: a narrow interval around an estimated buying probability gives a more precise estimate than a wide interval.

Notation: 95% CI [0.12, 0.28] gives the lower and upper limits of the interval. It does not mean that 95% of respondents lie within it.

9.7 Degrees of freedom

Degrees of freedom describe how much independent information is available for a statistical test. They are not the number of respondents.

Example: a test comparing several countries needs more degrees of freedom than a simple comparison between two groups.

Notation: χ²(11) = 24.6 reports a chi-square statistic of 24.6 with 11 degrees of freedom.

9.8 Percentage point

A percentage point is the direct difference between two percentages.

Example: an increase from 60% to 65% is an increase of 5 percentage points, not 5%.

Notation: +5 pp means an increase of five percentage points.

10 Software and reproducibility

Data preparation and statistical analysis were conducted in R (R Core Team, 2024), primarily using the tidyverse (Wickham et al., 2019).

11 Use of AI

We used OpenAI Codex (GPT-5.6 Sol) to:

  • support the generation and revision of R code;
  • suggest and review parts of the analytical workflow and statistical methods;
  • audit the analyses and correct identified issues; and
  • create dated backups before major changes.

The questionnaire and initial analysis plan were developed by the authors. All AI-assisted code, analyses and text were reviewed by the authors. Made with human intelligence, and actual 🧠.

12 About the authors

Bellegarde Scientific Consulting is a behavioural science consultancy that helps organisations understand and change behaviour related to environmental issues.

Behavioural science has demonstrated its ability to explain and change human behaviour. Yet its application is too often reduced to simplistic techniques detached from scientific evidence. At a time when climate change, public-health crises, disinformation and war propaganda all hinge on behaviour, superficial approaches are no longer sufficient.

Bellegarde emerged from this gap.

We apply behavioural science rigorously and ethically, connecting real-world challenges with leading international research to deliver pragmatic, evidence-based solutions.

13 Bibliography

The bibliography includes the theoretical sources underlying the questionnaire items, the survey and statistical methods used in the reports, and the principal software packages required to reproduce the analyses.

Ajzen, I. (1991). The theory of planned behavior. Organizational Behavior and Human Decision Processes, 50(2), 179–211. https://doi.org/10.1016/0749-5978(91)90020-T
Allaire, J. J., Teague, C., Xie, Y., & Dervieux, C. (2022). Quarto. Zenodo. https://doi.org/10.5281/zenodo.5960048
Arel-Bundock, V., Greifer, N., & Heiss, A. (2024). How to interpret statistical models using marginaleffects for r and python. Journal of Statistical Software, 111(9), 1–32. https://doi.org/10.18637/jss.v111.i09
Benjamini, Y., & Hochberg, Y. (1995). Controlling the false discovery rate: A practical and powerful approach to multiple testing. Journal of the Royal Statistical Society: Series B (Methodological), 57(1), 289–300. https://doi.org/10.1111/j.2517-6161.1995.tb02031.x
Bicchieri, C. (2006). The grammar of society: The nature and dynamics of social norms. Cambridge University Press. https://doi.org/10.1017/CBO9780511616037
Bicchieri, C. (2016). Norms in the wild: How to diagnose, measure, and change social norms. Oxford University Press. https://doi.org/10.1093/acprof:oso/9780190622046.001.0001
Brunson, J. C. (2020). Ggalluvial: Layered grammar for alluvial plots. Journal of Open Source Software, 5(49), 2017. https://doi.org/10.21105/joss.02017
Christensen, R. H. B. (2025). Ordinal: Regression models for ordinal data. https://CRAN.R-project.org/package=ordinal
Cialdini, R. B., Reno, R. R., & Kallgren, C. A. (1990). A focus theory of normative conduct: Recycling the concept of norms to reduce littering in public places. Journal of Personality and Social Psychology, 58(6), 1015–1026. https://doi.org/10.1037/0022-3514.58.6.1015
DeSimone, J. A., Harms, P. D., & DeSimone, A. J. (2015). Best practice recommendations for data screening. Journal of Organizational Behavior, 36(2), 171–181. https://doi.org/10.1002/job.1962
Dynata. (2026). Getting started with dynata+ sample. https://www.dynata.com/why-dynata/resources/blog/getting-started-with-dynata-sample/
Eagly, A. H., & Chaiken, S. (2007). The advantages of an inclusive definition of attitude. Social Cognition, 25(5), 582–602. https://doi.org/10.1521/soco.2007.25.5.582
Fishbein, M., & Ajzen, I. (2010). Predicting and changing behavior: The reasoned action approach. Psychology Press. https://doi.org/10.4324/9780203838020
Gohel, D., & Skintzos, P. (2026). Ggiraph: Make ggplot2 graphics interactive. https://CRAN.R-project.org/package=ggiraph
Iannone, R., Cheng, J., Schloerke, B., Hughes, E., Lauer, A., & Seo, J. (2026). Gt: Easily create presentation-ready display tables. https://CRAN.R-project.org/package=gt
Krosnick, J. A., & Presser, S. (2010). Question and questionnaire design. In P. V. Marsden & J. D. Wright (Eds), Handbook of survey research (2nd edn, pp. 263–313). Emerald Group Publishing.
Lumley, T. (2004). Analysis of complex survey samples. Journal of Statistical Software, 9(8), 1–19. https://doi.org/10.18637/jss.v009.i08
Meade, A. W., & Craig, S. B. (2012). Identifying careless responses in survey data. Psychological Methods, 17(3), 437–455. https://doi.org/10.1037/a0028085
Organisation for Economic Co-operation and Development. (2022). Integrity and security in the global research ecosystem (No. 130). OECD Publishing. https://doi.org/10.1787/1c416f43-en
R Core Team. (2024). R: A language and environment for statistical computing. R Foundation for Statistical Computing. https://www.R-project.org/
Rosseel, Y. (2012). Lavaan: An r package for structural equation modeling. Journal of Statistical Software, 48(2), 1–36. https://doi.org/10.18637/jss.v048.i02
Sparkman, G., & Walton, G. M. (2017). Dynamic norms promote sustainable behavior, even if it is counternormative. Psychological Science, 28(11), 1663–1674. https://doi.org/10.1177/0956797617719950
Tjur, T. (2009). Coefficients of determination in logistic regression models—a new proposal: The coefficient of discrimination. The American Statistician, 63(4), 366–372. https://doi.org/10.1198/tast.2009.08210
Tourangeau, R., Rips, L. J., & Rasinski, K. (2000). The psychology of survey response. Cambridge University Press. https://doi.org/10.1017/CBO9780511819322
United Nations, Department of Economic and Social Affairs, Population Division. (2024). World population prospects 2024: Summary of results (UN DESA/POP/2024/TR/NO. 9). United Nations. https://www.un.org/development/desa/pd/content/world-population-prospects-2024-dataset
Venables, W. N., & Ripley, B. D. (2002). Modern applied statistics with s (4th edn). Springer. https://www.stats.ox.ac.uk/pub/MASS4/
Wickham, H. (2016). ggplot2: Elegant graphics for data analysis. Springer-Verlag. https://ggplot2.tidyverse.org
Wickham, H., Averick, M., Bryan, J., Chang, W., McGowan, L. D., François, R., Grolemund, G., Hayes, A., Henry, L., Hester, J., Kuhn, M., Pedersen, T. L., Miller, E., Bache, S. M., Müller, K., Ooms, J., Robinson, D., Seidel, D. P., Spinu, V., … Yutani, H. (2019). Welcome to the tidyverse. Journal of Open Source Software, 4(43), 1686. https://doi.org/10.21105/joss.01686
Wilke, C. O. (2025). Ggridges: Ridgeline plots in ggplot2. https://CRAN.R-project.org/package=ggridges
Zeileis, A. (2004). Econometric computing with HC and HAC covariance matrix estimators. Journal of Statistical Software, 11(10), 1–17. https://doi.org/10.18637/jss.v011.i10

Citation

BibTeX citation:
@report{naczaj2026,
  author = {Naczaj, Dimitri and Bonetto, Éric},
  publisher = {Bellegarde Scientific Consulting for the WEEE Forum},
  title = {Fast-Tech {Consumer} {Study}},
  date = {2026},
  langid = {en-GB}
}
For attribution, please cite this work as:
Naczaj, D., & Bonetto, É. (2026). Fast-Tech Consumer Study. Bellegarde Scientific Consulting for the WEEE Forum.