Show R code
source("R/fast-tech-shared.R")WEEE Forum Fast-Tech Consumer Study
A multi-country study of fast tech purchasing, use and end-of-life behaviours among European consumers.
8 September 2026
This report presents descriptive findings from 10,245 respondents across 12 European countries.
Small and inexpensive electronic devices have become increasingly visible and easy to purchase, particularly through online marketplaces. Although these products can fulfill practical needs, their low price, limited perceived value and sometimes short period of use may encourage frequent purchasing, accumulation at home and inappropriate disposal. These patterns raise environmental, social and political questions, about resource consumption, electronic-waste prevention and the responsibilities of consumers, producers, retailers and online platforms.
The WEEE Forum and its participating members commissioned a European consumer study for International E-Waste Day 2026. The main objective is to examine fast tech consumption, such as ownership and purchasing, end-of-life decisions, motivations and influences. A second objective is to identify behavioural patterns and knowledge gaps that can feed consumer communication, collection strategies and policy recommendations.
The study covers 10,245 respondents across 12 European countries. Results are post-stratified to the age, gender and country distribution of the combined population aged 18–99. Weighting improves alignment on these observed characteristics but does not eliminate possible panel-selection, coverage or measurement bias. Comparisons therefore remain descriptive rather than causal.
The survey design, fieldwork, sample composition, weighting and data-processing procedures are documented in the methodology report.
The main research questions are:
Fast tech consumption
How widespread is fast tech ownership and purchasing, which product categories are most commonly acquired, and how many devices are bought and stored at home?
Drivers of purchasing behaviour
Which factors are associated with fast tech purchasing and future buying intentions?
Use and end-of-life pathways
What happens to fast tech devices after purchase? How many remain in use, why do consumers stop using them? To what extent are unused devices stored, reused, donated, sold, recycled or discarded through inappropriate waste streams?
Levers for more sustainable behaviour
Could greater durability, willingness to pay more, different replacement choices or improved collection convenience encourage consumers to reduce fast tech purchases and choose more sustainable alternatives?
Knowledge and policy relevance
How aware are consumers that fast tech products contain electronic components and that online platforms may have financial obligations for electronic-waste collection and recycling? How strongly do consumers support reduced consumption and stricter regulation about electronic waste?
household_cols <- c(
"Household_Charging & lighting devices",
"Household_High-tech",
"Household_Gadgets & lifestyle items",
"Household_E-vapes"
)
band_levels <- c("0", "1", "2 to 5", "6 to 9", "10 to 19", "20+")
detention_long <- df |>
select(analysis_weight, all_of(household_cols)) |>
pivot_longer(
cols = all_of(household_cols),
names_to = "Category",
values_to = "Band"
) |>
mutate(
Category = str_remove(Category, "Household_"),
Band = factor(Band, levels = band_levels)
)
# Ownership rates by category
detention_ownership <- detention_long |>
group_by(Category) |>
summarise(
pct = weighted_mean_safe(Band != "0", analysis_weight),
.groups = "drop"
)
format_ownership_percent <- function(cat) percent(
detention_ownership$pct[detention_ownership$Category == cat],
accuracy = 0.1
)
# Combined quantities across the three non-vape categories.
# Since Q4 records ranges rather than exact counts, each respondent's combined
# quantity is represented by a minimum and a maximum.
household_non_vape_cols <- household_cols[
household_cols != "Household_E-vapes"
]
household_band_min <- c(
"0" = 0,
"1" = 1,
"2 to 5" = 2,
"6 to 9" = 6,
"10 to 19" = 10,
"20+" = 20
)
household_band_max <- c(
"0" = 0,
"1" = 1,
"2 to 5" = 5,
"6 to 9" = 9,
"10 to 19" = 19,
"20+" = Inf
)
detention_combined_levels <- c(
"No item",
"Exactly 1 item",
"Definitely 2 to 5 items",
"Could be 2 to 5 or 6+ items",
"Definitely 6 or more items"
)
detention_combined <- df |>
transmute(
analysis_weight,
across(
all_of(household_non_vape_cols),
as.character
)
) |>
mutate(
total_min = rowSums(
across(
all_of(household_non_vape_cols),
\(x) unname(household_band_min[x])
)
),
total_max = rowSums(
across(
all_of(household_non_vape_cols),
\(x) unname(household_band_max[x])
)
),
Combined_total = case_when(
total_max == 0 ~ "No item",
total_min == 1 & total_max == 1 ~ "Exactly 1 item",
total_min >= 2 & total_max <= 5 ~ "Definitely 2 to 5 items",
total_min > 5 ~ "Definitely 6 or more items",
TRUE ~ "Could be 2 to 5 or 6+ items"
),
Combined_total = factor(
Combined_total,
levels = detention_combined_levels
)
)
detention_combined_summary <- detention_combined |>
group_by(Combined_total, .drop = FALSE) |>
summarise(
n = n(),
weighted_n = sum(analysis_weight),
.groups = "drop"
) |>
mutate(pct = weighted_n / sum(weighted_n)) |>
arrange(Combined_total)
detention_combined_pct <- setNames(
detention_combined_summary$pct,
as.character(detention_combined_summary$Combined_total)
)
pct_own_non_vape <- 1 - detention_combined_pct[["No item"]]
pct_definitely_six_plus <- detention_combined_pct[[
"Definitely 6 or more items"
]]
pct_definitely_two_five <- detention_combined_pct[[
"Definitely 2 to 5 items"
]]
pct_possible_two_five <- pct_definitely_two_five +
detention_combined_pct[["Could be 2 to 5 or 6+ items"]]Q4. How many of the following items are currently in your household (regardless of who bought them or when)?
Fast tech items are present in the vast majority of surveyed households. Charging and lighting devices lead with 82.6% of respondents owning at least one, followed by high-tech items (69.5%) and gadgets & lifestyle items (69.4%). E-vapes are considerably less widespread, owned by 27.6% of the sample, reflecting a different usage.
detention_long |>
group_by(Category) |>
summarise(
pct = weighted_mean_safe(Band != "0", analysis_weight),
.groups = "drop"
) |>
mutate(category_type = if_else(Category == "E-vapes", "E-vapes", "Other categories")) |>
ggplot(aes(x = reorder(Category, pct), y = pct, fill = category_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("Other categories" = bg_accent,"E-vapes" = bg_ink_32), guide = "none") +
scale_y_continuous(labels = percent_format(), expand = expansion(mult = c(0, 0.12))) +
coord_flip() +
labs(x = NULL, y = "% respondents owning at least one item")The quantity distributions differ markedly by category. E-vapes have the highest share of non-ownership, while the modal quantity among the three other categories is generally between two and five items.
detention_long |>
group_by(Category, Band, .drop = FALSE) |>
summarise(
n = n(),
weighted_n = sum(analysis_weight),
.groups = "drop_last"
) |>
mutate(
pct = weighted_n / sum(weighted_n),
band_type = if_else(
as.character(Band) == "0",
"No item",
"At least one item"
)
) |>
ungroup() |>
ggplot(
aes(
x = Band,
y = pct,
fill = band_type
)
) +
geom_col(
width = bg_bar_width
) +
geom_text(
aes(label = percent(pct, accuracy = 0.1)),
vjust = -0.4,
size = bg_size_label / .pt
) +
scale_fill_manual(
values = c(
"No item" = bg_ink_32,
"At least one item" = bg_accent
),
guide = "none"
) +
scale_y_continuous(
labels = percent_format(),
expand = expansion(mult = c(0, 0.12))
) +
facet_wrap(
~Category,
ncol = 2
) +
labs(
x = "Number of items",
y = NULL
) +
theme(
axis.text.x = element_text(
angle = 30,
hjust = 1
),
panel.spacing.y = grid::unit(28, "pt")
)Across charging and lighting devices, high-tech products, and gadgets and lifestyle items, 86.8% of respondents own at least one item. At least 44.1% definitely own six or more items.
Note: Because the questionnaire records a range for each category, the exact proportion owning two to five items in total cannot be identified. It lies between 14.1%, who are certainly in this range, and 37.6%, which additionally includes respondents whose category ranges could sum either to two to five or to six or more items.
detention_combined_summary |>
mutate(
total_type = case_when(
Combined_total == "No item" ~ "None",
Combined_total == "Could be 2 to 5 or 6+ items" ~ "Range uncertainty",
TRUE ~ "Classified total"
)
) |>
ggplot(aes(
x = pct,
y = fct_rev(Combined_total),
fill = total_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(
"None" = bg_ink_32,
"Range uncertainty" = bg_blue_50,
"Classified total" = bg_accent
),
guide = "none"
) +
scale_x_continuous(
labels = percent_format(),
expand = expansion(mult = c(0, 0.16))
) +
labs(
x = "% of respondents",
y = NULL
)detention_sociodemo_data <- df |>
transmute(
Age_group = as.character(Age_recoded_1),
Gender_group = recode(
as.character(Gender),
"98" = "No answer"
),
Employment_group = as.character(Employment),
Household_size = as.numeric(Nb_household),
analysis_weight,
detention_any_non_vape = if_any(
all_of(household_non_vape_cols),
~ as.character(.x) != "0"
)
)
summarise_ownership_dimension <- function(
variable,
dimension,
levels
) {
detention_sociodemo_data |>
transmute(
Group = as.character(
.data[[variable]]
),
analysis_weight,
outcome = as.integer(
detention_any_non_vape
)
) |>
filter(
!is.na(outcome),
Group %in% levels
) |>
group_by(Group) |>
summarise(
n = n(),
pct = weighted_mean_safe(outcome, analysis_weight),
.groups = "drop"
) |>
mutate(
Dimension = dimension,
Group = factor(
Group,
levels = levels
)
)
}
detention_overall <- weighted_mean_safe(
detention_sociodemo_data$detention_any_non_vape,
detention_sociodemo_data$analysis_weight
)
detention_desired_rows <- c(
paste(
"Age",
sociodemographic_age_levels,
sep = "___"
),
paste(
"Gender",
sociodemographic_gender_levels,
sep = "___"
),
paste(
"Employment",
sociodemographic_employment_levels,
sep = "___"
)
)
detention_sociodemo_summary <- bind_rows(
summarise_ownership_dimension(
"Age_group",
"Age",
sociodemographic_age_levels
),
summarise_ownership_dimension(
"Gender_group",
"Gender",
sociodemographic_gender_levels
),
summarise_ownership_dimension(
"Employment_group",
"Employment",
sociodemographic_employment_levels
)
) |>
mutate(
Dimension = factor(
Dimension,
levels = c(
"Age",
"Gender",
"Employment"
)
),
Group_plot = paste(
Dimension,
as.character(Group),
sep = "___"
),
Group_plot = factor(
Group_plot,
levels = rev(
detention_desired_rows
)
),
overall = detention_overall,
comparison = if_else(
pct >= overall,
"At or above overall",
"Below overall"
)
)
detention_household_model_data <-
detention_sociodemo_data |>
transmute(
Household_size,
analysis_weight,
outcome = as.integer(
detention_any_non_vape
)
) |>
drop_na()
detention_household_design <- survey::svydesign(
ids = ~1,
weights = ~analysis_weight,
data = detention_household_model_data
)
detention_household_model <- survey::svyglm(
outcome ~ Household_size,
design = detention_household_design,
family = quasibinomial()
)
detention_household_grid <- tibble(
Household_size = seq(
min(
detention_household_model_data$
Household_size
),
max(
detention_household_model_data$
Household_size
),
length.out = 100
)
)
detention_household_prediction <- predict(
detention_household_model,
newdata = detention_household_grid,
type = "link"
)
detention_household_prediction_fit <- as.numeric(
detention_household_prediction
)
detention_household_prediction_se <- as.numeric(
survey::SE(detention_household_prediction)
)
detention_household_curve <-
detention_household_grid |>
mutate(
pct = plogis(
detention_household_prediction_fit
),
lower = plogis(
detention_household_prediction_fit -
1.96 *
detention_household_prediction_se
),
upper = plogis(
detention_household_prediction_fit +
1.96 *
detention_household_prediction_se
)
)
detention_household_observed <-
detention_household_model_data |>
group_by(Household_size) |>
summarise(
n = n(),
pct = weighted_mean_safe(outcome, analysis_weight),
.groups = "drop"
)
detention_age_young <-
detention_sociodemo_summary |>
filter(
Dimension == "Age",
Group == "18-29"
) |>
pull(pct)
detention_age_old <-
detention_sociodemo_summary |>
filter(
Dimension == "Age",
Group == "65-99"
) |>
pull(pct)
detention_employment_high <-
detention_sociodemo_summary |>
filter(Dimension == "Employment") |>
slice_max(
pct,
n = 1,
with_ties = FALSE
)
detention_employment_low <-
detention_sociodemo_summary |>
filter(Dimension == "Employment") |>
slice_min(
pct,
n = 1,
with_ties = FALSE
)Ownership of at least one fast tech item (excluding e-vapes) is high across all socio-demographic groups. It ranges from 94.2% among respondents aged 18–29 to 80.3% among those aged 65–99. By employment status, it is highest among student respondents (96.0%) and lowest among other respondents (77.7%).
Basically, it means that almost all 18-39 years old and almost all students detain at least one fast tech item.
Note: These are population-weighted, unadjusted descriptive comparisons. Gender categories with non-substantive answers and employment respondents who preferred not to answer are excluded.
detention_sociodemo_summary |>
ggplot(aes(
x = pct,
y = Group_plot,
colour = comparison
)) +
geom_vline(
xintercept =
detention_sociodemo_summary$
overall[[1]],
colour = bg_ink_32,
linewidth = bg_lw_hairline,
linetype = "dashed"
) +
geom_segment(
aes(
x = overall,
xend = pct,
yend = Group_plot
),
colour = bg_ink_32,
linewidth = bg_lw_line
) +
geom_point(size = 3) +
geom_text(
aes(
label = percent(
pct,
accuracy = 0.1
)
),
hjust = -0.35,
colour = bg_ink,
size = bg_size_label / .pt
) +
scale_colour_manual(
values = c(
"At or above overall" = bg_accent,
"Below overall" = bg_blue
),
guide = "none"
) +
scale_x_continuous(
labels = percent_format(),
limits = c(0, 1),
expand = expansion(
mult = c(0, 0.06)
)
) +
scale_y_discrete(
labels = \(x) {
str_remove(x, "^.*___")
}
) +
facet_grid(
rows = vars(Dimension),
scales = "free_y",
space = "free_y"
) +
labs(
x = "% owning at least one item",
y = NULL
) +
theme(
strip.text.y = element_text(
angle = 0
)
)Household size is treated as a continuous predictor. The curve below shows the population-weighted estimated probability of ownership, with the weighted observed rate for each household size overlaid.
ggplot(
detention_household_curve,
aes(x = Household_size, y = pct)
) +
geom_ribbon(
aes(ymin = lower, ymax = upper),
fill = bg_accent_20,
alpha = bg_alpha_mute
) +
geom_line(
colour = bg_accent,
linewidth = bg_lw_line
) +
geom_point(
data = detention_household_observed,
colour = bg_ink,
aes(size = n)
) +
scale_size_continuous(
name = "N",
range = c(2, 5)
) +
scale_x_continuous(
breaks = 1:10
) +
scale_y_continuous(
labels = percent_format(),
limits = c(0, 1),
expand = expansion(
mult = c(0, 0.04)
)
) +
labs(
x = "Household size",
y = "Estimated probability of ownership"
)buying_band_levels <- c(
"0", "1", "2 to 5", "6 to 9", "10 to 19", "20+"
)
n_total <- nrow(df)
n_ever_bought <- sum(df$Buyer == "Buyer", na.rm = TRUE)
pct_ever_bought <- weighted_mean_safe(
df$Buyer == "Buyer",
df$analysis_weight
)
n_recent_buyers <- sum(df$Buy_12months == "Buyer", na.rm = TRUE)
pct_recent_buyers <- weighted_mean_safe(
df$Buy_12months == "Buyer",
df$analysis_weight
)Non-buyers are respondents who declared never having bought any fast tech device.
buyer_demographics_data <- df |>
transmute(
Buyer_group = recode(
Buyer,
"Buyer" = "Buyers",
"Non buyer" = "Non-buyers"
),
Age = as.numeric(Age),
Gender = as.character(Gender),
Country,
analysis_weight,
Income = coalesce(
Income_Norway,
Income_Romania,
Income_Poland,
Income_Switzerland,
Income_UK,
Income_Euro
)
) |>
group_by(Country) |>
mutate(
income_lower = income_lower_bound(Income),
income_bracket_position =
assign_income_bracket_position(
Country,
income_lower
),
income_n_brackets = n_distinct(
income_lower,
na.rm = TRUE
),
income_eur_equivalent = case_when(
is.na(income_lower) ~ NA_real_,
Country == "Switzerland" &
income_bracket_position == income_n_brackets ~ 135000,
TRUE ~ 5000 +
(income_bracket_position - 1) * 10000
)
) |>
ungroup()
buyer_demographics_summary <- buyer_demographics_data |>
filter(!is.na(Buyer_group)) |>
group_by(Buyer_group) |>
summarise(
n = n(),
age_mean = weighted_mean_safe(Age, analysis_weight),
age_sd = weighted_sd_safe(Age, analysis_weight),
income_median = weighted_quantile_safe(
income_eur_equivalent, analysis_weight, probs = 0.5
),
income_q1 = weighted_quantile_safe(
income_eur_equivalent, analysis_weight, probs = 0.25
),
income_q3 = weighted_quantile_safe(
income_eur_equivalent, analysis_weight, probs = 0.75
),
.groups = "drop"
)
buyer_gender_summary <- buyer_demographics_data |>
filter(
Gender %in% c(
"Female",
"Male",
"Non-binary"
)
) |>
group_by(Buyer_group, Gender) |>
summarise(
n = n(),
weighted_n = sum(analysis_weight),
.groups = "drop_last"
) |>
mutate(pct = weighted_n / sum(weighted_n)) |>
ungroup()
buyer_demographics_design <- survey::svydesign(
ids = ~1,
weights = ~analysis_weight,
data = buyer_demographics_data |>
mutate(Buyer_binary = as.integer(Buyer_group == "Buyers"))
)
buyer_age_test <- survey::svyttest(
Age ~ Buyer_binary,
design = subset(
buyer_demographics_design,
!is.na(Age) & !is.na(Buyer_binary)
)
)
buyer_gender_test <- survey::svychisq(
~Buyer_group + Gender,
design = subset(
buyer_demographics_design,
Gender %in% c("Female", "Male")
),
statistic = "F"
)
buyer_age_gender_model_data <- buyer_demographics_data |>
filter(
!is.na(Age),
!is.na(Buyer_group),
Gender %in% c("Female", "Male")
) |>
mutate(
Buyer_binary = as.integer(Buyer_group == "Buyers"),
Gender = factor(Gender, levels = c("Female", "Male")),
Age_centered = Age - weighted_mean_safe(Age, analysis_weight)
)
buyer_age_gender_design <- survey::svydesign(
ids = ~1,
weights = ~analysis_weight,
data = buyer_age_gender_model_data
)
buyer_age_gender_model <- survey::svyglm(
Buyer_binary ~ Age_centered * Gender,
design = buyer_age_gender_design,
family = quasibinomial()
)
buyer_age_gender_interaction_test <- survey::regTermTest(
buyer_age_gender_model,
~Age_centered:Gender
)
buyer_age_gender_interaction_p <- as.numeric(
buyer_age_gender_interaction_test$p
)[1]
buyer_income_test <- survey::svyranktest(
income_eur_equivalent ~ Buyer_binary,
design = subset(
buyer_demographics_design,
!is.na(income_eur_equivalent) & !is.na(Buyer_binary)
),
test = "wilcoxon"
)
buyer_age_mean <- setNames(
buyer_demographics_summary$age_mean,
buyer_demographics_summary$Buyer_group
)
buyer_income_median <- setNames(
buyer_demographics_summary$income_median,
buyer_demographics_summary$Buyer_group
)
buyer_income_q1 <- setNames(
buyer_demographics_summary$income_q1,
buyer_demographics_summary$Buyer_group
)
buyer_income_q3 <- setNames(
buyer_demographics_summary$income_q3,
buyer_demographics_summary$Buyer_group
)
buyer_female_pct <- setNames(
buyer_gender_summary$pct[
buyer_gender_summary$Gender == "Female"
],
buyer_gender_summary$Buyer_group[
buyer_gender_summary$Gender == "Female"
]
)
buyer_group_colours <- c(
"Buyers" = bg_accent,
"Non-buyers" = bg_blue
)
buyer_age_gender_data <- buyer_demographics_data |>
filter(
!is.na(Age),
Gender %in% c(
"Female",
"Male"
)
) |>
mutate(
Buyer_group = factor(
Buyer_group,
levels = c(
"Buyers",
"Non-buyers"
)
),
group_y = case_when(
Buyer_group == "Buyers" ~ 1,
Buyer_group == "Non-buyers" ~ 2
),
gender_direction = if_else(
Gender == "Female",
1,
-1
),
box_y = group_y +
gender_direction * 0.13
)
buyer_age_axis_labels <- buyer_age_gender_data |>
count(Buyer_group, name = "n") |>
mutate(
axis_label = paste0(
Buyer_group,
"\nN = ",
format_count(n)
)
) |>
select(
Buyer_group,
axis_label
) |>
deframe()
buyer_age_gender_density <- buyer_age_gender_data |>
group_by(
Buyer_group,
Gender,
group_y,
gender_direction
) |>
group_modify(
\(.x, .y) {
density_estimate <- density(
.x$Age,
weights = .x$analysis_weight / sum(.x$analysis_weight),
from = 18,
to = 90,
n = 512
)
tibble(
Age = density_estimate$x,
density = density_estimate$y
)
}
) |>
ungroup() |>
mutate(
density_height =
density / max(density) * 0.38,
density_y = group_y +
gender_direction * density_height
)
buyer_age_gender_means <- buyer_age_gender_data |>
group_by(Buyer_group, Gender) |>
summarise(
Age = weighted_mean_safe(Age, analysis_weight),
box_y = first(box_y),
.groups = "drop"
)Buyers are younger than non-buyers: their mean age is 47.7 years, compared with 59.5 years among non-buyers (p < .001). Women account for 50.2% of buyers and 59.3% of non-buyers; buyer status also differs by gender (p < .001). The age gradient does not differ significantly between women and men (p = 0.799).
ggplot() +
geom_hline(
yintercept = c(1, 2),
colour = bg_ink_32,
linewidth = bg_lw_hairline
) +
geom_ribbon(
data = buyer_age_gender_density,
aes(
x = Age,
ymin = group_y,
ymax = density_y,
fill = Buyer_group,
alpha = Gender,
group = interaction(
Buyer_group,
Gender
)
),
colour = NA
) +
geom_boxplot(
data = buyer_age_gender_data,
aes(
x = Age,
y = box_y,
weight = analysis_weight,
group = interaction(
Buyer_group,
Gender
)
),
orientation = "y",
width = 0.09,
outlier.shape = NA,
fill = bg_surface,
colour = bg_ink,
alpha = 0.85,
linewidth = bg_lw_hairline
) +
geom_point(
data = buyer_age_gender_means,
aes(
x = Age,
y = box_y
),
shape = 21,
size = 2.8,
stroke = 0.7,
fill = bg_surface,
colour = bg_ink
) +
scale_fill_manual(
values = buyer_group_colours,
guide = "none"
) +
scale_alpha_manual(
name = NULL,
breaks = c(
"Female",
"Male"
),
labels = c(
"Women (above)",
"Men (below)"
),
values = c(
"Female" = 0.78,
"Male" = 0.34
),
guide = guide_legend(
override.aes = list(
fill = bg_accent,
colour = NA
)
)
) +
scale_x_continuous(
breaks = seq(0, 90, by = 10),
limits = c(0, 90),
expand = expansion(mult = c(0.01, 0.01))
) +
scale_y_continuous(
breaks = c(1, 2),
labels = c(
buyer_age_axis_labels[["Buyers"]],
buyer_age_axis_labels[["Non-buyers"]]
),
limits = c(0.55, 2.45),
expand = expansion(mult = c(0, 0))
) +
labs(
x = "Age",
y = NULL,
caption = str_wrap(
paste(
"Women: above centre line; men: below.",
"White circles: means; boxes: medians and IQRs."
),
width = 88
)
) +
theme(
panel.grid.major.y = element_blank(),
panel.grid.minor = element_blank(),
legend.position = "top"
)The median approximate income bracket is €35k in both groups, but the buyers’ distribution is shifted towards higher brackets: its middle 50% ranges from €25k to €55k, compared with €15k to €45k among non-buyers (p < .001). It means that, overall, buyers seem to have higher revenues.
Q5. Have you ever bought small and inexpensive electronic devices, excluding e-vapes?
Fast tech purchasing is widespread in the surveyed population. Overall, 9,154 respondents (87.4%) have bought fast tech at least once, while 1,091 (12.6%) report never having bought these products.
buyer_status <- df |>
filter(!is.na(Buyer)) |>
group_by(Buyer) |>
summarise(
n = n(),
weighted_n = sum(analysis_weight),
.groups = "drop"
) |>
mutate(
Status = recode(
Buyer,
"Buyer" = "Ever bought fast tech",
"Non buyer" = "Never bought fast tech"
),
pct = weighted_n / sum(weighted_n)
)
buyer_status |>
ggplot(aes(x = reorder(Status, 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.12))
) +
coord_flip() +
labs(x = NULL, y = "% of respondents")recent_purchase_long <- df |>
select(analysis_weight, all_of(recent_purchase_cols)) |>
pivot_longer(
cols = all_of(recent_purchase_cols),
names_to = "Category",
values_to = "Band"
) |>
mutate(
Category = str_remove(Category, "^Buy_12months_"),
Band = factor(
as.character(Band),
levels = buying_band_levels
)
)
recent_purchase_summary <- recent_purchase_long |>
group_by(Category) |>
summarise(
n_respondents = sum(!is.na(Band)),
n_bought = sum(Band != "0", na.rm = TRUE),
pct = weighted_mean_safe(Band != "0", analysis_weight),
.groups = "drop"
)
recent_purchase_combined_levels <- c(
"No purchase",
"Exactly 1 item",
"Definitely 2 to 5 items",
"Could be 2 to 5 or 6+ items",
"Definitely 6 or more items"
)
recent_purchase_combined <- df |>
transmute(
analysis_weight,
across(
all_of(recent_purchase_cols),
as.character
)
) |>
mutate(
total_min = rowSums(
across(
all_of(recent_purchase_cols),
\(x) unname(household_band_min[x])
)
),
total_max = rowSums(
across(
all_of(recent_purchase_cols),
\(x) unname(household_band_max[x])
)
),
Combined_total = case_when(
total_max == 0 ~ "No purchase",
total_min == 1 & total_max == 1 ~ "Exactly 1 item",
total_min >= 2 & total_max <= 5 ~ "Definitely 2 to 5 items",
total_min > 5 ~ "Definitely 6 or more items",
TRUE ~ "Could be 2 to 5 or 6+ items"
),
Combined_total = factor(
Combined_total,
levels = recent_purchase_combined_levels
)
)
recent_purchase_combined_summary <- recent_purchase_combined |>
group_by(Combined_total, .drop = FALSE) |>
summarise(
n = n(),
weighted_n = sum(analysis_weight),
.groups = "drop"
) |>
mutate(pct = weighted_n / sum(weighted_n)) |>
arrange(Combined_total)
recent_purchase_combined_pct <- setNames(
recent_purchase_combined_summary$pct,
as.character(recent_purchase_combined_summary$Combined_total)
)
pct_no_recent_purchase <- recent_purchase_combined_pct[["No purchase"]]
pct_exactly_one_recent_purchase <- recent_purchase_combined_pct[[
"Exactly 1 item"
]]
pct_definitely_six_plus_recent_purchase <- recent_purchase_combined_pct[[
"Definitely 6 or more items"
]]
pct_definitely_two_five_recent_purchase <- recent_purchase_combined_pct[[
"Definitely 2 to 5 items"
]]
pct_possible_two_five_recent_purchase <-
pct_definitely_two_five_recent_purchase +
recent_purchase_combined_pct[["Could be 2 to 5 or 6+ items"]]Q3. How many of the following items did you personally buy, over the last 12 months?
8,205 respondents (77.6%) purchased at least one fast tech item during the previous 12 months (August 2025 - July 2026).
Charging and lighting devices are most bought (68.0% of respondents), while gadgets and lifestyle items (57.5%) and high-tech products (51.9%) were bought by a little over half of the respondents.
Note: since e-vapes are banned from most european countries, we didn’t ask the question about this category
recent_purchase_summary |>
ggplot(aes(x = reorder(Category, 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(),
limits = c(0, NA),
expand = expansion(mult = c(0, 0.12))
) +
coord_flip() +
labs(
x = NULL,
y = "% of all respondents"
)Charging and lighting devices have the highest overall purchasing rate, with 32.8% of respondents having bought 2 to 5 items during the past year.
recent_purchase_long |>
group_by(Category, Band, .drop = FALSE) |>
summarise(
n = n(),
weighted_n = sum(analysis_weight),
.groups = "drop_last"
) |>
mutate(
pct = weighted_n / sum(weighted_n),
band_type = if_else(
as.character(Band) == "0",
"No purchase",
"At least one purchase"
)
) |>
ungroup() |>
ggplot(
aes(
x = Band,
y = pct,
fill = band_type
)
) +
geom_col(width = bg_bar_width) +
geom_text(
aes(
label = if_else(
pct >= 0.02,
percent(pct, accuracy = 0.1),
""
)
),
vjust = -0.4,
size = bg_size_label / .pt
) +
scale_fill_manual(
values = c(
"No purchase" = bg_ink_32,
"At least one purchase" = bg_accent
),
guide = "none"
) +
scale_y_continuous(
labels = percent_format(),
expand = expansion(mult = c(0, 0.13))
) +
facet_wrap(
~Category,
ncol = 1
) +
labs(
x = "Number of items purchased",
y = "% of respondents"
) +
theme(
axis.text.x = element_text(
angle = 30,
hjust = 1
),
panel.spacing.y = grid::unit(32, "pt")
)About 77.6% of respondents bought at least one fast tech item during the last 12 months (excluding e-vapes). 10.8% bought exactly one item, while at least 20.1% bought six or more.
The exact share buying two to five items in total lies between 18.9% and 46.7%, depending on the exact counts within the ranges selected for each category.
Note: Q3 uses quantity ranges for each category. Combined totals therefore preserve the resulting uncertainty rather than imputing an exact number within each range.
recent_purchase_combined_summary |>
mutate(
total_type = case_when(
Combined_total == "No purchase" ~ "None",
Combined_total == "Could be 2 to 5 or 6+ items" ~ "Range uncertainty",
TRUE ~ "Classified total"
)
) |>
ggplot(aes(
x = pct,
y = fct_rev(Combined_total),
fill = total_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(
"None" = bg_ink_32,
"Range uncertainty" = bg_blue_50,
"Classified total" = bg_accent
),
guide = "none"
) +
scale_x_continuous(
labels = percent_format(),
expand = expansion(mult = c(0, 0.16))
) +
labs(
x = "% of respondents",
y = NULL
)intention_cols <- c(
"Charging & lighting devices_Intend to buy",
"High-tech_Intend to buy",
"Gadgets & lifestyle items_Intend to buy"
)
intention_summary <- df |>
select(analysis_weight, all_of(intention_cols)) |>
pivot_longer(
cols = all_of(intention_cols),
names_to = "Category",
values_to = "Intention"
) |>
filter(!is.na(Intention)) |>
mutate(
Category = str_remove(Category, "_Intend to buy$")
) |>
group_by(Category) |>
summarise(
n_presented = n(),
n_intended = sum(Intention == "Intended"),
pct = weighted_mean_safe(Intention == "Intended", analysis_weight),
.groups = "drop"
)
intention_percent_by_category <- setNames(
intention_summary$pct,
intention_summary$Category
)Q8/Q9. Let’s talk about the most recent [Category A/B] you bought. Q8a/Q9a. Did you intend to buy it?
Buying intentions are high for all three product categories. Among respondents to whom the category was presented, 77.8% intended to buy charging and lighting devices, 78.4% intended to buy high-tech products, and 75.1% intended to buy gadgets and lifestyle items.
intention_summary |>
ggplot(aes(x = reorder(Category, 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(),
limits = c(0, 1),
expand = expansion(mult = c(0, 0.08))
) +
coord_flip() +
labs(
x = NULL,
y = "% intending to buy"
)item_categories <- c(
"Charging & lighting devices",
"High-tech",
"Gadgets & lifestyle items"
)
item_reason_suffixes <- c(
"For work, study or everyday use",
"As a temporary replacement",
"I wanted a newer version",
"As a spare device",
"I bought it even though I didn't really need it",
"It was a gift for someone else",
"There was no other product / no other choice",
"Other"
)
item_reason_cols <- unlist(
lapply(
item_categories,
\(category) paste0(category, "_", item_reason_suffixes)
),
use.names = FALSE
)
item_reason_summary <- df |>
select(analysis_weight, all_of(item_reason_cols)) |>
pivot_longer(
cols = all_of(item_reason_cols),
names_to = "Variable",
values_to = "Value"
) |>
filter(!is.na(Value)) |>
mutate(
Category = str_extract(Variable, "^[^_]+"),
Reason = str_remove(Variable, "^[^_]+_"),
selected = is_selected(Value)
) |>
group_by(Category, Reason) |>
summarise(
n = sum(selected),
denominator = n(),
pct = weighted_mean_safe(selected, analysis_weight),
.groups = "drop"
) |>
mutate(
Reason_plot = str_wrap(Reason, width = 36)
)
item_reason_combined_summary <- df |>
mutate(respondent_id = row_number()) |>
select(
respondent_id,
analysis_weight,
all_of(item_reason_cols)
) |>
pivot_longer(
cols = all_of(item_reason_cols),
names_to = "Variable",
values_to = "Value"
) |>
mutate(
Reason = str_remove(
Variable,
"^[^_]+_"
),
presented = !is.na(Value),
selected = is_selected(Value)
) |>
group_by(
respondent_id,
Reason
) |>
summarise(
analysis_weight = first(analysis_weight),
presented = any(presented),
selected = any(selected),
.groups = "drop"
) |>
filter(presented) |>
group_by(Reason) |>
summarise(
n = sum(selected),
denominator = n(),
pct = weighted_mean_safe(selected, analysis_weight),
.groups = "drop"
) |>
arrange(desc(pct)) |>
mutate(
Reason_plot = str_wrap(
Reason,
width = 42
)
)
item_reason_combined_pct <- setNames(
item_reason_combined_summary$pct,
item_reason_combined_summary$Reason
)
format_item_reason_percent <- function(
category,
reason
) {
format_percent(
item_reason_summary$pct[
item_reason_summary$Category == category &
item_reason_summary$Reason == reason
]
)
}Q8b/Q9b. Why did you buy it?
Reasons differ by category, even though fast tech items are mostly bought for use, as a replacement or as a spare device. High-tech items are more often reported as purchases motivated by wanting a newer version (28.7%), while gadgets and lifestyle items are more often reported as purchases made without a real need (18.3%).
Note: these were multiple-response questions, so respondents could select more than one reason and percentages do not sum to 100%.
item_reason_summary |>
mutate(
Reason_plot = str_wrap(Reason, width = 42)
) |>
ggplot(
aes(
x = pct,
y = fct_reorder(Reason_plot, pct)
)
) +
geom_col(
width = 0.52,
fill = bg_accent
) +
geom_text(
aes(label = percent(pct, accuracy = 0.1)),
hjust = -0.15,
size = bg_size_label / .pt
) +
scale_x_continuous(
labels = percent_format(),
expand = expansion(mult = c(0, 0.16))
) +
scale_y_discrete(
expand = expansion(add = 0.35)
) +
facet_wrap(
~Category,
ncol = 1,
scales = "free_y"
) +
labs(
x = "% selecting the reason",
y = NULL
) +
theme(
axis.text.y = element_text(
lineheight = 0.9
),
panel.spacing.y = grid::unit(32, "pt")
)When the three fast tech categories are combined, having a temporary replacement is the most widely reported buying reason (40.0%). This is followed by buying an item as a spare device (39.6%), for work, study or everyday use (36.4%), and wanting a newer version (34.4%).
Nearly a quarter of recent buyers selected buying an item despite not really needing it (22.7%), for at least one category.
Note: Each reason is counted no more than once per respondent, even when it was selected for several categories. Respondents could select multiple reasons, so the percentages do not sum to 100%.
item_reason_combined_summary |>
ggplot(aes(
x = pct,
y = fct_reorder(Reason_plot, pct)
)) +
geom_col(
width = bg_bar_width,
fill = bg_accent
) +
geom_text(
aes(label = percent(pct, accuracy = 0.1)),
hjust = -0.15,
size = bg_size_label / .pt
) +
scale_x_continuous(
labels = percent_format(),
expand = expansion(mult = c(0, 0.16))
) +
labs(
x = "% of eligible recent buyers",
y = NULL
)general_reason_cols <- c(
"They are more affordable",
"They are the only available option",
"They are easily available or showcased",
"I read positive reviews about them",
"Promotions or special deals",
"People I trust recommend them",
"I see them in ads or on social media",
"Curiosity, for fun, or trying something new",
"Other...88",
"I don’t know...89"
)
general_reason_summary <- df |>
select(analysis_weight, all_of(general_reason_cols)) |>
pivot_longer(
cols = all_of(general_reason_cols),
names_to = "Reason",
values_to = "Value"
) |>
filter(!is.na(Value)) |>
mutate(
Reason = recode(
Reason,
"Other...88" = "Other",
"I don’t know...89" = "I don’t know"
),
selected = is_selected(Value)
) |>
group_by(Reason) |>
summarise(
n = sum(selected),
denominator = n(),
pct = weighted_mean_safe(selected, analysis_weight),
.groups = "drop"
) |>
arrange(desc(pct)) |>
mutate(
Reason_plot = str_wrap(Reason, width = 38)
)
general_reason_percent <- setNames(
general_reason_summary$pct,
general_reason_summary$Reason
)Q10. Generally speaking, what makes you buy small and inexpensive electronic devices rather than more expensive alternatives?
Half of respondents designated price as a purchasing driver (55.2%). Together with promotions (35.8%), this makes affordability the leading reported reason Availability or product visibility is the second reason (28.5%).
Social influences seem to have a smaller impact: positive reviews by 21.2%, recommendations from trusted people by 15.9%, and advertising or social media by 11.8%.
Note: this was also a multiple-response question.
general_reason_summary |>
ggplot(aes(
x = pct,
y = fct_reorder(Reason_plot, pct)
)) +
geom_col(width = bg_bar_width, fill = bg_accent) +
geom_text(
aes(label = percent(pct, accuracy = 0.1)),
hjust = -0.15,
size = bg_size_label / .pt
) +
scale_x_continuous(
labels = percent_format(),
expand = expansion(mult = c(0, 0.16))
) +
labs(
x = "% of respondents who have ever bought fast tech",
y = NULL
)purchase_channel_cols <- c(
"On the brand’s website",
"Online stores, marketplaces, social media",
"Tobacconist, convenience store",
"Physical stores, outdoor stall, market store",
"At the airport or a train station",
"As gifts, professional giveaways or merch",
"Second hand platform",
"I don’t remember...99",
"Other...98"
)
purchase_channel_summary <- df |>
select(analysis_weight, all_of(purchase_channel_cols)) |>
pivot_longer(
cols = all_of(purchase_channel_cols),
names_to = "Channel",
values_to = "Value"
) |>
filter(!is.na(Value)) |>
mutate(
Channel = recode(
Channel,
"I don’t remember...99" = "I don’t remember",
"Other...98" = "Other"
),
selected = is_selected(Value)
) |>
group_by(Channel) |>
summarise(
n = sum(selected),
denominator = n(),
pct = weighted_mean_safe(selected, analysis_weight),
.groups = "drop"
) |>
arrange(desc(pct)) |>
mutate(
Channel_plot = str_wrap(Channel, width = 40)
)
purchase_channel_pct <- setNames(
purchase_channel_summary$pct,
purchase_channel_summary$Channel
)Q11. Where do you usually get your small and inexpensive electronic devices (no matter the category)?
Online stores, marketplaces and social media are the most frequently reported purchase channels, selected by 52.1% of buyers. Physical stores, outdoor stalls and market stores follow closely (48.0%), while 25.2% buy directly from brand websites. All other channels were selected by fewer than one buyer in seven.
Note: Respondents could select more than one purchase channel, so percentages do not sum to 100%.
purchase_channel_summary |>
mutate(
response_type = if_else(
Channel %in% c("I don’t remember", "Other"),
"Non-substantive response",
"Purchase channel"
)
) |>
ggplot(aes(
x = pct,
y = fct_reorder(Channel_plot, pct),
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(
"Purchase channel" = bg_accent,
"Non-substantive response" = bg_ink_32
),
guide = "none"
) +
scale_x_continuous(
labels = percent_format(),
expand = expansion(mult = c(0, 0.16))
) +
labs(
x = "% of buyers",
y = NULL
)still_use_summary <- df |>
filter(
Buy_12months == "Buyer",
!is.na(`12months_still use`)
) |>
mutate(
Band = factor(
as.character(`12months_still use`),
levels = buying_band_levels
)
) |>
group_by(Band, .drop = FALSE) |>
summarise(
n = n(),
weighted_n = sum(analysis_weight),
.groups = "drop"
) |>
mutate(pct = weighted_n / sum(weighted_n))
still_use_percent_by_band <- setNames(
still_use_summary$pct,
as.character(still_use_summary$Band)
)Q12. Among all the small and inexpensive electronic devices you’ve bought during the last 12 months, how many do you still personally use today?
Among respondents who purchased fast tech during the last 12 months, 58.6% report that two to five items are still in use; 20.7% report one item, while 3.4% report that none of the items are still in use.
Note: we’ve only asked about the items recently bought (less than a year).
still_use_summary |>
ggplot(aes(x = Band, 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.12))
) +
labs(
x = "Number of items still in use",
y = "% of respondents who purchased fast tech\nin the last 12 months"
)shortest_use_levels <- c(
"I got rid of it without ever using it",
"Single-use",
"Less than a week",
"Less than a month",
"1 to 6 months",
"6 to 12 months",
"12 months or more",
"I don’t know / don’t remember"
)
shortest_use_summary <- summarise_response_distribution(
df,
"Shortest_used",
shortest_use_levels
)
pct_shortest_under_month <- shortest_use_summary |>
filter(
Response %in% c(
"I got rid of it without ever using it",
"Single-use",
"Less than a week",
"Less than a month"
)
) |>
summarise(pct = sum(pct)) |>
pull(pct)
shortest_use_pct <- setNames(
shortest_use_summary$pct,
as.character(shortest_use_summary$Response)
)
pct_shortest_within_six_months <-
pct_shortest_under_month +
shortest_use_pct[["1 to 6 months"]]Q13. Think about the small and inexpensive electronic devices you’ve ever had (excluding disposable e-cigarettes). What is the shortest period of time you have used one of them before discarding it?
More than a third of previous buyers (38.6%) recalled their shortest-lived fast tech device was discarded without being used, after a single use or within one month. Overall, 57.9% declared that their shortest-lived fast tech device lasted no more than six months.
shortest_use_summary |>
mutate(
response_type = if_else(
Response == "I don’t know / don’t remember",
"Don’t know",
"Reported duration"
)
) |>
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(
"Reported duration" = bg_accent,
"Don’t know" = 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 = 38)
) +
labs(
x = "% of previous buyers",
y = NULL
)disposed_long <- df |>
select(analysis_weight, all_of(disposed_cols)) |>
pivot_longer(
all_of(disposed_cols),
names_to = "Category",
values_to = "Code"
) |>
filter(!is.na(Code)) |>
mutate(
Category = str_remove(
Category,
"^12months_disposed_"
),
Category = recode(
Category,
"Gadget and lifestyle items" =
"Gadgets & lifestyle items"
),
# The recoded file stores the six response categories
# as numeric codes from 1 to 6.
Band = recode(
as.character(Code),
"1" = "0",
"2" = "1",
"3" = "2 to 5",
"4" = "6 to 9",
"5" = "10 to 19",
"6" = "20+"
),
Band = factor(
Band,
levels = eol_band_levels
)
)
disposed_summary <- disposed_long |>
group_by(Category) |>
summarise(
n_eligible = n(),
n_disposed = sum(Band != "0"),
pct = weighted_mean_safe(Band != "0", analysis_weight),
.groups = "drop"
)
format_disposed_percent <- function(category) {
format_percent(
disposed_summary$pct[
disposed_summary$Category == category
]
)
}
disposed_code_min <- c(
"1" = 0,
"2" = 1,
"3" = 2,
"4" = 6,
"5" = 10,
"6" = 20
)
disposed_code_max <- c(
"1" = 0,
"2" = 1,
"3" = 5,
"4" = 9,
"5" = 19,
"6" = Inf
)
disposed_combined_levels <- c(
"No item disposed of",
"Exactly 1 item",
"Definitely 2 to 5 items",
"Could be 2 to 5 or 6+ items",
"Definitely 6 or more items"
)
disposed_combined <- df |>
transmute(
analysis_weight,
across(
all_of(disposed_non_vape_cols),
as.character
)
) |>
filter(
if_all(
all_of(disposed_non_vape_cols),
~ !is.na(.x)
)
) |>
mutate(
total_min = rowSums(
across(
all_of(disposed_non_vape_cols),
\(x) unname(disposed_code_min[x])
)
),
total_max = rowSums(
across(
all_of(disposed_non_vape_cols),
\(x) unname(disposed_code_max[x])
)
),
Combined_total = case_when(
total_max == 0 ~ "No item disposed of",
total_min == 1 & total_max == 1 ~ "Exactly 1 item",
total_min >= 2 & total_max <= 5 ~ "Definitely 2 to 5 items",
total_min > 5 ~ "Definitely 6 or more items",
TRUE ~ "Could be 2 to 5 or 6+ items"
),
Combined_total = factor(
Combined_total,
levels = disposed_combined_levels
)
)
disposed_combined_summary <- disposed_combined |>
group_by(Combined_total, .drop = FALSE) |>
summarise(
n = n(),
weighted_n = sum(analysis_weight),
.groups = "drop"
) |>
mutate(pct = weighted_n / sum(weighted_n)) |>
arrange(Combined_total)
disposed_combined_pct <- setNames(
disposed_combined_summary$pct,
as.character(disposed_combined_summary$Combined_total)
)
pct_any_disposed_non_vape <- 1 -
disposed_combined_pct[["No item disposed of"]]
pct_exactly_one_disposed_non_vape <- disposed_combined_pct[[
"Exactly 1 item"
]]
pct_definitely_six_plus_disposed_non_vape <- disposed_combined_pct[[
"Definitely 6 or more items"
]]
pct_definitely_two_five_disposed_non_vape <- disposed_combined_pct[[
"Definitely 2 to 5 items"
]]
pct_possible_two_five_disposed_non_vape <-
pct_definitely_two_five_disposed_non_vape +
disposed_combined_pct[["Could be 2 to 5 or 6+ items"]]Q14. Over the last 12 months, how many of the following items have you personally disposed of?
Among respondents who have ever bought fast tech, 68.6% disposed of at least one charging or lighting device during the past year, making this category the most widely disposed of, which is coherent with the quantity owned, purchased, and buying intentions.
Half respondents disposed of at least one high-tech item (47.7%) or gadget and lifestyle item (48.4%). The proportion was lower for e-vapes, at 28.8%.
disposed_summary |>
mutate(
category_type = if_else(
Category == "E-vapes",
"E-vapes",
"Other categories"
)
) |>
ggplot(aes(
x = reorder(Category, pct),
y = pct,
fill = category_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(
"Other categories" = bg_accent,
"E-vapes" = bg_ink_32
),
guide = "none"
) +
scale_y_continuous(
labels = percent_format(),
limits = c(0, NA),
expand = expansion(mult = c(0, 0.12))
) +
coord_flip() +
labs(
x = NULL,
y = "% disposing of at least one item"
)Charging and lighting devices are disposed of more frequently and in larger numbers than the other categories, which, again, is consistent with previous results on buying behaviour, ownership and purchase intentions. For high-tech products and gadgets and lifestyle items, reporting no disposal remains the most frequent individual response.
category_order <- c(
"Charging & lighting devices",
"Gadgets & lifestyle items",
"High-tech",
"E-vapes"
)
disposed_long |>
group_by(Category, Band, .drop = FALSE) |>
summarise(n = n(), weighted_n = sum(analysis_weight), .groups = "drop_last") |>
group_by(Category) |>
mutate(pct = weighted_n / sum(weighted_n)) |>
ungroup() |>
mutate(
Category = factor(
Category,
levels = category_order
),
band_type = if_else(
as.character(Band) == "0",
"No item disposed of",
"At least one item disposed of"
)
) |>
ggplot(aes(
x = Band,
y = pct,
fill = band_type
)) +
geom_col(width = bg_bar_width) +
geom_text(
aes(
label = if_else(
pct >= 0.02,
percent(pct, accuracy = 0.1),
""
)
),
vjust = -0.4,
size = bg_size_label / .pt
) +
scale_fill_manual(
values = c(
"No item disposed of" = bg_ink_32,
"At least one item disposed of" = bg_accent
),
guide = "none"
) +
scale_y_continuous(
labels = percent_format(),
expand = expansion(mult = c(0, 0.14))
) +
facet_wrap(
~Category,
ncol = 2
) +
labs(
x = "Number of items disposed of",
y = "% of previous buyers"
) +
theme(
axis.text.x = element_text(
angle = 30,
hjust = 1
),
panel.spacing.y = grid::unit(32, "pt")
)Across the three non-vape categories, 76.0% of previous buyers disposed of at least one fast tech item during the last 12 months. 16.3% disposed of exactly one item, while at least 17.3% disposed of six or more.
The exact share disposing of two to five items in total lies between 20.6% and 42.4%, depending on the exact counts within each category range.
Note: Combined quantities exclude e-vapes and use previous buyers with valid answers for all three categories. Since Q14 records ranges, combined totals preserve uncertainty rather than imputing exact counts.
disposed_combined_summary |>
mutate(
total_type = case_when(
Combined_total == "No item disposed of" ~ "None",
Combined_total == "Could be 2 to 5 or 6+ items" ~ "Range uncertainty",
TRUE ~ "Classified total"
)
) |>
ggplot(aes(
x = pct,
y = fct_rev(Combined_total),
fill = total_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(
"None" = bg_ink_32,
"Range uncertainty" = bg_blue_50,
"Classified total" = bg_accent
),
guide = "none"
) +
scale_x_continuous(
labels = percent_format(),
expand = expansion(mult = c(0, 0.16))
) +
labs(
x = "% of previous buyers",
y = NULL
)stopped_reason_summary <- df |>
select(analysis_weight, all_of(stopping_reason_cols)) |>
pivot_longer(
all_of(stopping_reason_cols),
names_to = "Reason",
values_to = "Value"
) |>
filter(!is.na(Value)) |>
mutate(
Reason = recode(
Reason,
"Other...114" = "Other"
),
selected = is_selected(Value)
) |>
group_by(Reason) |>
summarise(
n = sum(selected),
denominator = n(),
pct = weighted_mean_safe(selected, analysis_weight),
.groups = "drop"
) |>
arrange(desc(pct))
format_stopping_reason_percent <- function(reason) {
format_percent(
stopped_reason_summary$pct[
stopped_reason_summary$Reason == reason
]
)
}Q15. What are the main reasons why you stopped using your small and inexpensive electronic devices?
Product failure is the main reason for stopping use. More than half of respondents (53.3%) reported that an item broke or became defective, 35.8% said that an item stopped working despite appearing physically intact, and 6.3% reported the item became dangerous, underlying some defect.
A smaller proportion no longer needed the item (18.3%) or considered it outdated or obsolete (13.2%).
Note: Respondents could select up to two reasons.
stopped_reason_summary |>
mutate(
Reason_plot = str_wrap(Reason, width = 42)
) |>
ggplot(aes(
x = pct,
y = fct_reorder(Reason_plot, pct)
)) +
geom_col(width = bg_bar_width, fill = bg_accent) +
geom_text(
aes(label = percent(pct, accuracy = 0.1)),
hjust = -0.15,
size = bg_size_label / .pt
) +
scale_x_continuous(
labels = percent_format(),
expand = expansion(mult = c(0, 0.15))
) +
labs(
x = "% of eligible respondents",
y = NULL
)disposal_method_summary <- df |>
select(analysis_weight, all_of(disposal_method_cols)) |>
pivot_longer(
all_of(disposal_method_cols),
names_to = "Method",
values_to = "Value"
) |>
filter(!is.na(Value)) |>
mutate(
Method = recode(
Method,
"Other...124" = "Other",
"I don’t remember...125" =
"I don’t remember"
),
selected = is_selected(Value)
) |>
group_by(Method) |>
summarise(
n = sum(selected),
denominator = n(),
pct = weighted_mean_safe(selected, analysis_weight),
.groups = "drop"
) |>
arrange(desc(pct))
disposal_method_percent <- setNames(
disposal_method_summary$pct,
disposal_method_summary$Method
)
disposal_profile_summary <- disposal_response_data |>
group_by(Profile) |>
summarise(
n = n(),
weighted_n = sum(analysis_weight),
.groups = "drop"
) |>
mutate(
Profile = factor(
Profile,
levels = disposal_profile_levels
),
pct = weighted_n / sum(weighted_n)
) |>
arrange(Profile)
disposal_profile_pct <- setNames(
disposal_profile_summary$pct,
as.character(disposal_profile_summary$Profile)
)
n_disposal_respondents <- nrow(
disposal_response_data
)
n_single_disposal_method <- sum(
disposal_response_data$n_selected == 1
)
pct_single_disposal_method <-
weighted_mean_safe(
disposal_response_data$n_selected == 1,
disposal_response_data$analysis_weight
)
n_multiple_disposal_methods <- sum(
disposal_response_data$n_selected > 1
)
pct_multiple_disposal_methods <-
weighted_mean_safe(
disposal_response_data$n_selected > 1,
disposal_response_data$analysis_weight
)
disposal_unique_summary <- disposal_response_data |>
filter(n_selected == 1) |>
select(
analysis_weight,
all_of(c(
disposal_recycling_reuse_cols,
disposal_waste_cols,
disposal_kept_cols
))
) |>
pivot_longer(
-analysis_weight,
names_to = "Method",
values_to = "selected"
) |>
filter(selected) |>
mutate(
Method = recode(
Method,
"Other...124" = "Other",
"I don’t remember...125" =
"I don’t remember"
)
) |>
group_by(Method) |>
summarise(
n = n(),
weighted_n = sum(analysis_weight),
.groups = "drop"
) |>
mutate(pct = weighted_n / sum(weighted_n)) |>
arrange(desc(pct))Q16. Thinking about all the devices you have stopped using, what have you done with them?
Just like casual electronic devices, keeping unused items at home is the most common reported behaviour (29.3% of buyers). 27.4% report bringing devices to a recycling centre or municipal waste facility, and 18.9% report using a store collection point. Reuse options were selected less often: 11.2% gave devices away or donated them and 3.4% sold them.
Inappropriate disposal seem to remain frequent: 22.5% reported throwing an item into general household waste, 20.8% into the plastic waste bin, and 6.5% into a street bin.
Note: the plastic-waste-bin option was not displayed in Switzerland.
disposal_method_summary |>
mutate(
method_type = case_when(
Method %in% c(
"I brought them to a recycling centre / municipal waste facility",
"I brought them to a recycling point in a store",
"I gave them away or donated",
"I sold them"
) ~ "Recycling or reuse",
Method %in% c(
"I kept them",
"I don’t remember",
"Other"
) ~ "Kept, other or unknown",
TRUE ~ "Waste disposal"
),
Method_plot = str_wrap(Method, width = 44)
) |>
ggplot(aes(
x = pct,
y = fct_reorder(Method_plot, pct),
fill = method_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(
name = NULL,
values = c(
"Recycling or reuse" = bg_accent,
"Kept, other or unknown" = bg_ink_32,
"Waste disposal" = bg_pink
),
guide="none"
) +
scale_x_continuous(
labels = percent_format(),
expand = expansion(mult = c(0, 0.16))
) +
labs(
x = "% of buyers",
y = NULL
)If we group the disposal methods, we see that 31.9% reported recycling or reuse methods only, whereas 26.9% reported waste-disposal methods only. A further 15.5% reported only keeping devices, and 25.6% combined methods belonging to more than one group.
Note: “Other” and “I don’t remember” are excluded.
disposal_profile_summary |>
ggplot(aes(
x = pct,
y = fct_rev(Profile),
fill = Profile
)) +
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(
"Recycling or reuse only" = bg_accent,
"Waste disposal only" = bg_pink,
"Kept only" = bg_ink_32,
"Mixed methods" = bg_blue
),
guide = "none"
) +
scale_x_continuous(
labels = percent_format(),
expand = expansion(mult = c(0, 0.16))
) +
labs(
x = "% of previous buyers",
y = NULL
)disposal_profile_country_summary <- disposal_response_data |>
left_join(
df |>
transmute(
respondent_id = row_number(),
Country
),
by = "respondent_id"
) |>
mutate(
Profile = factor(
Profile,
levels = disposal_profile_levels
)
) |>
group_by(
Country,
Profile,
.drop = FALSE
) |>
summarise(
n = n(),
weighted_n = sum(country_weight),
.groups = "drop_last"
) |>
mutate(pct = weighted_n / sum(weighted_n)) |>
ungroup()
disposal_profile_country_order <-
disposal_profile_country_summary |>
filter(Profile == "Recycling or reuse only") |>
arrange(pct) |>
pull(Country)
disposal_profile_country_extremes <-
disposal_profile_country_summary |>
filter(
Profile %in% c(
"Recycling or reuse only",
"Waste disposal only"
)
) |>
group_by(Profile) |>
summarise(
highest_country = Country[which.max(pct)],
highest_pct = max(pct),
lowest_country = Country[which.min(pct)],
lowest_pct = min(pct),
.groups = "drop"
)
country_recycling_profile_extremes <-
disposal_profile_country_extremes |>
filter(Profile == "Recycling or reuse only")
country_bin_profile_high <-
disposal_profile_country_extremes |>
filter(Profile == "Waste disposal only")The distribution between disposal habits differs across countries. Reporting recycling or reuse only ranges from 25.7% in Romania to 47.8% in Switzerland.
Note: Percentages are calculated within each country. “Other” and “I don’t remember” answers are excluded. Respondents selecting identifiable methods from more than one route are classified as using mixed methods.
disposal_profile_country_summary |>
mutate(
Country = factor(
Country,
levels = disposal_profile_country_order
),
Profile_plot = recode(
as.character(Profile),
"Waste disposal only" = "Bin disposal only"
),
Profile_plot = factor(
Profile_plot,
levels = c(
"Recycling or reuse only",
"Mixed methods",
"Kept only",
"Bin disposal only"
)
)
) |>
ggplot(aes(
x = pct,
y = Country,
fill = Profile_plot
)) +
geom_col(
width = bg_bar_width,
position = position_stack(reverse = TRUE)
) +
geom_text(
aes(
label = if_else(
pct >= 0.05,
percent(pct, accuracy = 0.1),
""
)
),
position = position_stack(
vjust = 0.5,
reverse = TRUE
),
colour = bg_ink,
size = bg_size_label / .pt
) +
scale_fill_manual(
name = NULL,
values = c(
"Recycling or reuse only" = bg_accent,
"Mixed methods" = bg_blue,
"Kept only" = bg_ink_32,
"Bin disposal only" = bg_pink
),
drop = FALSE
) +
scale_x_continuous(
labels = percent_format(),
breaks = seq(0, 1, by = 0.25),
expand = expansion(mult = c(0, 0.02))
) +
labs(
x = "% within each country",
y = NULL
) +
theme(
legend.position = "top",
panel.grid.major.y = element_blank()
)5,779 respondents (66.1%) selected only one disposal option. Within this group, keeping the devices and taking them to a recycling centre or municipal waste facility were the two most frequently reported outcomes.
Note: The percentages below sum to 100%, but apply only to respondents who selected exactly one identifiable option. “Other” and “I don’t remember” are excluded. The analysis excludes 2,993 respondents (33.9%) who reported more than one identifiable disposal method. This share is larger than the “Mixed methods” profile because respondents can select several methods belonging to the same profile, such as two recycling routes.
disposal_unique_summary |>
mutate(
method_type = case_when(
Method %in% c(
"I brought them to a recycling centre / municipal waste facility",
"I brought them to a recycling point in a store",
"I gave them away or donated",
"I sold them"
) ~ "Recycling or reuse",
Method == "I kept them" ~ "Kept",
TRUE ~ "Waste disposal"
),
Method_plot = str_wrap(Method, width = 44)
) |>
ggplot(aes(
x = pct,
y = fct_reorder(Method_plot, pct),
fill = method_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(
"Recycling or reuse" = bg_accent,
"Kept" = bg_ink_32,
"Waste disposal" = bg_pink
),
guide = "none"
) +
scale_x_continuous(
labels = percent_format(),
expand = expansion(mult = c(0, 0.16))
) +
labs(
x = "% of single-option respondents",
y = NULL
)disposal_motivation_summary <- df |>
select(analysis_weight, all_of(disposal_motivation_cols)) |>
pivot_longer(
all_of(disposal_motivation_cols),
names_to = "Motivation",
values_to = "Value"
) |>
filter(!is.na(Value)) |>
mutate(
Motivation = recode(
Motivation,
"didn’t know where else to put it" =
"I didn’t know where else to put it",
"Other...132" = "Other"
),
selected = is_selected(Value)
) |>
group_by(Motivation) |>
summarise(
n = sum(selected),
denominator = n(),
pct = weighted_mean_safe(selected, analysis_weight),
.groups = "drop"
) |>
arrange(desc(pct))
disposal_motivation_percent <- setNames(
disposal_motivation_summary$pct,
disposal_motivation_summary$Motivation
)
disposal_profile_motivation_summary <- df |>
mutate(
respondent_id = row_number()
) |>
select(
respondent_id,
analysis_weight,
all_of(disposal_motivation_cols)
) |>
pivot_longer(
all_of(disposal_motivation_cols),
names_to = "Motivation",
values_to = "Value"
) |>
filter(!is.na(Value)) |>
mutate(
Motivation = recode(
Motivation,
"didn’t know where else to put it" =
"I didn’t know where else to put it",
"Other...132" = "Other"
),
selected = is_selected(Value)
) |>
inner_join(
disposal_response_data |>
select(
respondent_id,
Profile
),
by = "respondent_id"
) |>
group_by(
Profile,
Motivation
) |>
summarise(
n = sum(selected),
denominator = n(),
pct = weighted_mean_safe(selected, analysis_weight),
.groups = "drop"
) |>
mutate(
Profile = factor(
Profile,
levels = disposal_profile_levels
),
Motivation = factor(
Motivation,
levels = rev(
disposal_motivation_summary$Motivation
)
),
label_colour = if_else(
pct >= 0.38,
bg_white,
bg_ink
)
)
format_profile_motivation_percent <- function(
profile,
motivation
) {
format_percent(
disposal_profile_motivation_summary$pct[
disposal_profile_motivation_summary$Profile ==
profile &
disposal_profile_motivation_summary$Motivation ==
motivation
]
)
}Q17. Why did you choose this or these solutions?
Habit is the leading reported explanation for respondents’ end-of-life choices: 38.6% selected what they usually do with that kind of waste. Environmental protection is the second reason (34.0%), while convenience (33.6%) and proximity (16.1%) are also quite commonly selected.
disposal_motivation_summary |>
mutate(
Motivation_plot = str_wrap(
Motivation,
width = 44
)
) |>
ggplot(aes(
x = pct,
y = fct_reorder(Motivation_plot, pct)
)) +
geom_col(width = bg_bar_width, fill = bg_accent) +
geom_text(
aes(label = percent(pct, accuracy = 0.1)),
hjust = -0.15,
size = bg_size_label / .pt
) +
scale_x_continuous(
labels = percent_format(),
expand = expansion(mult = c(0, 0.16))
) +
labs(
x = "% of previous buyers",
y = NULL
)The motivations reported for end-of-life choices vary with the disposal profile. Among respondents reporting recycling or reuse only, environmental protection (52.3%) and habit (51.0%) are the two leading motivations.
For respondents reporting waste disposal only, ease is the leading motivation (36.1%), followed by habit (30.6%).
Interestingly, 20.6% selected environmental protection despite reporting only waste-disposal routes, which may indicate uncertainty or lack of knowledge about appropriate e-waste disposal.
Keeping devices without reporting another identifiable outcome is primarily associated with ease (40.5%), while 16.9% reported not really thinking about their choice.
Note: Percentages are calculated within each mutually exclusive profile based on identifiable outcomes; “Other” and “I don’t remember” do not define a profile. Respondents could select several motivations, so percentages within a profile do not sum to 100%. The associations are descriptive and don’t establish causation.
disposal_profile_motivation_summary |>
ggplot(aes(
x = Profile,
y = Motivation,
fill = pct
)) +
geom_tile(
colour = bg_surface,
linewidth = 1
) +
geom_text(
aes(
label = percent(
pct,
accuracy = 0.1
),
colour = label_colour
),
size = bg_size_label / .pt
) +
scale_fill_bg_c(
palette = "seq",
name = "% within profile",
breaks = c(0, 0.25, 0.5),
limits = c(0, 0.55),
labels = percent_format()
) +
scale_colour_identity() +
scale_x_discrete(
labels = \(x) str_wrap(
x,
width = 12
)
) +
scale_y_discrete(
labels = \(x) str_wrap(
x,
width = 40
)
) +
labs(
x = NULL,
y = NULL
) +
theme(
axis.text.x = element_text(
lineheight = 0.9
),
panel.grid = element_blank(),
legend.position = "top"
)Respondents were classified as non-buyers when they answered No, never to Q5 on ever having bought a small and inexpensive electronic device. The achieved sample contains 1,091 non-buyers (10.6% of respondents). After population weighting, they represent 12.6% of the population covered by the study.
nonbuyer_reason_cols <- c(
"I don’t know where to buy them",
"I don’t need them or I already own similar items",
"prefer higher-quality, longer-lasting alternatives",
"Because of their impact on the environment",
"Because of their social impact",
"Someone else buys electronic devices at home",
"Other...36",
"I don’t know...37"
)
nonbuyer_reason_summary <- nonbuyers |>
select(analysis_weight, all_of(nonbuyer_reason_cols)) |>
pivot_longer(
all_of(nonbuyer_reason_cols),
names_to = "Reason",
values_to = "Value"
) |>
filter(!is.na(Value)) |>
mutate(
Reason = recode(
Reason,
"prefer higher-quality, longer-lasting alternatives" =
"I prefer higher-quality, longer-lasting alternatives",
"Other...36" = "Other",
"I don’t know...37" = "I don’t know"
),
selected = is_selected(Value)
) |>
group_by(Reason) |>
summarise(
n = sum(selected),
denominator = n(),
pct = weighted_mean_safe(selected, analysis_weight),
.groups = "drop"
) |>
arrange(desc(pct))
format_nonbuyer_reason_percent <- function(reason) {
format_percent(
nonbuyer_reason_summary$pct[
nonbuyer_reason_summary$Reason == reason
]
)
}Q6. Which of these describe why you have never bought any small and inexpensive electronic device?
Perceived lack of need or already owning similar products are the main reasons for never purchasing fast tech, selected by almost half of non-buyers.
Preference for higher-quality and longer-lasting alternatives ranks second (26.8%). A further 14.3% were unable to identify a specific reason.
Environmental concerns were selected by 10.6%, whereas social impact concerns were mentioned less frequently (3.1%).
Note: Because respondents could select more than one answer, the percentages do not sum to 100%.
nonbuyer_reason_summary |>
mutate(
Reason_plot = str_wrap(Reason, width = 44)
) |>
ggplot(aes(
x = pct,
y = fct_reorder(Reason_plot, pct)
)) +
geom_col(width = bg_bar_width, fill = bg_accent) +
geom_text(
aes(label = percent(pct, accuracy = 0.1)),
hjust = -0.15,
size = bg_size_label / .pt
) +
scale_x_continuous(
labels = percent_format(),
expand = expansion(mult = c(0, 0.16))
) +
labs(
x = "% of non-buyers",
y = NULL
)exposure_levels <- c(
"Everyday",
"At least once a week",
"At least once a month",
"Few times a year",
"Less or never"
)
exposure_comparison_summary <- df |>
filter(
!is.na(`SeeFast-tech`),
Buyer %in% c("Buyer", "Non buyer")
) |>
mutate(
Buyer_group = recode(
Buyer,
"Buyer" = "Buyers",
"Non buyer" = "Non-buyers"
),
Buyer_group = factor(
Buyer_group,
levels = c("Non-buyers", "Buyers")
),
Frequency = factor(
`SeeFast-tech`,
levels = exposure_levels
)
) |>
group_by(Buyer_group, Frequency, .drop = FALSE) |>
summarise(
n = n(),
weighted_n = sum(analysis_weight),
.groups = "drop_last"
) |>
group_by(Buyer_group) |>
mutate(pct = weighted_n / sum(weighted_n)) |>
ungroup()
# Retains the non-buyer subset used in the accompanying text.
nonbuyer_exposure_summary <- exposure_comparison_summary |>
filter(Buyer_group == "Non-buyers") |>
arrange(Frequency)
format_nonbuyer_exposure_percent <- function(frequency) {
format_percent(
nonbuyer_exposure_summary$pct[
nonbuyer_exposure_summary$Frequency == frequency
]
)
}
pct_exposed_weekly_by_group <- exposure_comparison_summary |>
filter(
Frequency %in% c(
"Everyday",
"At least once a week"
)
) |>
group_by(Buyer_group) |>
summarise(
pct = sum(pct),
.groups = "drop"
) |>
deframe()Q7. How often do you come across small and inexpensive electronic devices? (At work, at friends’, in shops, on the web or social media…)
More than half of non-buyers report being very rarely or never exposed to fast tech items (54.7%), which contrasts with 74.4% of buyers reporting being exposed daily or at least once a week.
Note: These measures report buyers and non-buyers perceptions. They can be exposed without noticing or remembering.
exposure_comparison_summary |>
mutate(
Frequency_plot = factor(
Frequency,
levels = rev(exposure_levels)
)
) |>
ggplot(aes(
x = Frequency_plot,
y = pct,
fill = Buyer_group
)) +
geom_col(
position = position_dodge(width = 0.74),
width = 0.64
) +
geom_text(
aes(label = percent(pct, accuracy = 0.1)),
position = position_dodge(width = 0.74),
hjust = -0.15,
size = bg_size_label / .pt
) +
scale_fill_manual(
name = NULL,
values = c(
"Buyers" = bg_accent,
"Non-buyers" = bg_accent_50
),
breaks = c(
"Buyers",
"Non-buyers"
)
) +
scale_y_continuous(
labels = percent_format(),
expand = expansion(mult = c(0, 0.16))
) +
coord_flip() +
labs(
x = NULL,
y = "% within each group"
)The forthcoming results describe a certain degree of indifference among an important proportion of the respondents regarding fast tech and its environmental impact, which does not seem to be perceived as a problem.
satisfaction_levels <- c(
"Very dissatisfied",
"Dissatisfied",
"Neither satisfied nor dissatisfied",
"Satisfied",
"Very satisfied"
)
satisfaction_summary <- summarise_response_distribution(
df,
"Satisfaction",
satisfaction_levels
)
pct_satisfied <- satisfaction_summary |>
filter(Response %in% c("Satisfied", "Very satisfied")) |>
summarise(pct = sum(pct)) |>
pull(pct)
pct_dissatisfied <- satisfaction_summary |>
filter(Response %in% c("Dissatisfied", "Very dissatisfied")) |>
summarise(pct = sum(pct)) |>
pull(pct)Q18. Overall, thinking back on the small and inexpensive devices you used, you would say you are…
Only 8.4% declared to be unsatisfied of their fast tech devices. There’s actually a strong majority being satisfied (60.9%), while the rest (30.7%) express a neutral opinion.
Note: Question 18 was shown only to respondents who had previously bought fast tech.
satisfaction_summary |>
ggplot(aes(x = Response, 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.12))
) +
labs(x = NULL, y = "% of previous buyers") +
theme(
axis.text.x = element_text(angle = 25, hjust = 1)
)Q19. When you bought those small and inexpensive devices, would you have been willing to pay more for similar items that you could use over a longer time period?
Even though most of them report to be satisfied with they fast tech items, a majority of buyers (80.3%) would have been willing to pay more for longer-lasting alternatives. More than half of the buyers are willing to pay more for some items, rather than for most or all purchases.
pay_more_summary |>
mutate(
response_type = if_else(
as.character(Response) == "No",
"No",
"Other responses"
)
) |>
ggplot(aes(
x = Response,
y = pct,
fill = response_type
)) +
geom_col(width = bg_bar_width) +
geom_text(
aes(label = percent(pct, accuracy = 0.1)),
vjust = -0.4,
size = bg_size_label / .pt
) +
scale_fill_manual(
values = c(
"Other responses" = bg_accent,
"No" = bg_ink_32
),
guide = "none"
) +
scale_y_continuous(
labels = percent_format(),
expand = expansion(mult = c(0, 0.12))
) +
labs(
x = NULL,
y = "% of previous buyers"
) +
theme(
axis.text.x = element_text(
angle = 25,
hjust = 1
)
)replacement_summary <- summarise_response_distribution(
df,
"Replace",
replacement_choice_levels
)
pct_replace_inexpensive <- replacement_summary |>
filter(Response %in% c(
"Buy the exact same small and inexpensive model",
"Buy another small and inexpensive device"
)) |>
summarise(pct = sum(pct)) |>
pull(pct)Q20. If you had to replace a small and inexpensive electronic device that broke, you would…
If a fast tech device broke, 59.1% of previous buyers would replace it with the same model or another small and inexpensive device. By contrast, 33.2% would move to a more expensive alternative, while 6.5% would not replace the device.
That results echoes with the result on device satisfaction, showing that more than half of the buyers are satisfied with their fast tech devices. Since it brings overall satisfaction, it is logical to be willing to replace one’s fast tech device by another one, if not the same. There are still interrogation as to why most of the respondents would have been willing to pay more to replace some by a more durable device.
replacement_summary |>
mutate(Response_plot = str_wrap(Response, width = 38)) |>
ggplot(aes(
x = pct,
y = fct_reorder(Response_plot, pct)
)) +
geom_col(width = bg_bar_width, fill = bg_accent) +
geom_text(
aes(label = percent(pct, accuracy = 0.1)),
hjust = -0.15,
size = bg_size_label / .pt
) +
scale_x_continuous(
labels = percent_format(),
expand = expansion(mult = c(0, 0.16))
) +
labs(x = "% of previous buyers", y = NULL)lifespan_expectation_levels <- c(
"Shorter lifespan",
"Expected lifespan",
"Longer lifespan"
)
quality_expectation_levels <- c(
"Lower quality",
"Expected quality",
"Higher quality"
)
lifespan_expectation_summary <- summarise_response_distribution(
df,
"Global_Lifespan",
lifespan_expectation_levels
) |>
mutate(Measure = "Lifespan")
quality_expectation_data <- df |>
mutate(
Global_Quality = recode(
Global_Quality,
"Hgher quality" = "Higher quality"
)
)
quality_expectation_summary <- summarise_response_distribution(
quality_expectation_data,
"Global_Quality",
quality_expectation_levels
) |>
mutate(Measure = "Quality")
product_expectation_summary <- bind_rows(
lifespan_expectation_summary,
quality_expectation_summary
)
extract_product_expectation_proportion <- function(
measure,
response
) {
product_expectation_summary |>
filter(
Measure == measure,
Response == response
) |>
pull(pct)
}
pct_lifespan_met_or_exceeded <-
product_expectation_summary |>
filter(
Measure == "Lifespan",
Response %in% c(
"Expected lifespan",
"Longer lifespan"
)
) |>
summarise(pct = sum(pct)) |>
pull(pct)
pct_quality_met_or_exceeded <-
product_expectation_summary |>
filter(
Measure == "Quality",
Response %in% c(
"Expected quality",
"Higher quality"
)
) |>
summarise(pct = sum(pct)) |>
pull(pct)Q21. Globally, would you say that your small and inexpensive electronic devices…
Q21a. …have a shorter lifespan than you expected, the lifespan you expected, or a longer lifespan than you expected?
Q21b. …are of lower quality than you expected, the quality you expected, or higher quality than you expected?
The results are similar across the two dimensions. Around one quarter report outcomes below their expectations (26.8% for lifespan and 23.5% for quality), whereas around one in ten report outcomes above their expectations (10.5% and 8.0%, respectively).
The interesting result is that a majority of previous buyers consider that fast tech devices meet or exceed their expectations: 73.2% for lifespan and 76.5% for quality.
product_expectation_summary |>
mutate(
assessment = case_when(
Response %in% c(
"Shorter lifespan",
"Lower quality"
) ~ "Below expectations",
Response %in% c(
"Expected lifespan",
"Expected quality"
) ~ "As expected",
TRUE ~ "Above expectations"
)
) |>
ggplot(aes(
x = pct,
y = fct_rev(Response),
fill = assessment
)) +
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(
"Below expectations" = bg_pink,
"As expected" = bg_ink_32,
"Above expectations" = bg_accent
),
guide = "none"
) +
scale_x_continuous(
labels = percent_format(),
expand = expansion(mult = c(0, 0.16))
) +
facet_wrap(
~Measure,
ncol = 1,
scales = "free_y"
) +
labs(
x = "% of previous buyers",
y = NULL
) +
theme(
panel.spacing.y = grid::unit(26, "pt")
)environment_comparison_levels <- c(
"Less harmful",
"Equally harmful",
"More harmful"
)
lifespan_comparison_levels <- c(
"Shorter lifespan",
"Similar lifespan",
"Greater lifespan"
)
environment_comparison_summary <- summarise_response_distribution(
df,
"Comparison_Environmental impact",
environment_comparison_levels
) |>
mutate(Comparison = "Environmental impact")
lifespan_comparison_summary <- summarise_response_distribution(
df,
"Comparison_Lifespan",
lifespan_comparison_levels
) |>
mutate(Comparison = "Lifespan")
alternative_comparison_summary <- bind_rows(
environment_comparison_summary,
lifespan_comparison_summary
)
q22_joint_summary <- df |>
filter(
!is.na(`Comparison_Environmental impact`),
!is.na(Comparison_Lifespan)
) |>
group_by(
Environmental_impact = `Comparison_Environmental impact`,
Lifespan = Comparison_Lifespan
) |>
summarise(
n = n(),
weighted_n = sum(analysis_weight),
.groups = "drop"
) |>
mutate(
pct = weighted_n / sum(weighted_n),
Environmental_impact = factor(
Environmental_impact,
levels = environment_comparison_levels
),
Lifespan = factor(
Lifespan,
levels = lifespan_comparison_levels
)
)
q22_joint_top <- q22_joint_summary |>
slice_max(pct, n = 1, with_ties = FALSE)
q22_joint_unfavourable_pct <- q22_joint_summary |>
filter(
Environmental_impact == "More harmful",
Lifespan == "Shorter lifespan"
) |>
pull(pct)
extract_alternative_comparison_proportion <- function(
comparison,
response
) {
alternative_comparison_summary |>
filter(
Comparison == comparison,
Response == response
) |>
pull(pct)
}
pct_environment_equal_or_less <-
extract_alternative_comparison_proportion(
"Environmental impact",
"Less harmful"
) +
extract_alternative_comparison_proportion(
"Environmental impact",
"Equally harmful"
)
pct_environment_more_harmful <-
extract_alternative_comparison_proportion(
"Environmental impact",
"More harmful"
)
pct_lifespan_shorter_alternative <-
extract_alternative_comparison_proportion(
"Lifespan",
"Shorter lifespan"
)Q22. Compared to more expensive alternatives, you would say that small and inexpensive electronic devices tend to…
Most respondents (79.0%) consider fast tech devices equally or less harmful to the environment than more expensive alternatives. Only 21.0% perceive them as more harmful.
By contrast, 45.8% expect fast tech devices to have a shorter lifespan than more expensive alternatives. Respondents therefore appear more conscious of a durability disadvantage than of a greater environmental impact.
alternative_comparison_summary |>
mutate(
assessment = case_when(
Response %in% c(
"More harmful",
"Shorter lifespan"
) ~ "Less favourable",
Response %in% c(
"Equally harmful",
"Similar lifespan"
) ~ "Equivalent",
TRUE ~ "More favourable"
)
) |>
ggplot(aes(
x = pct,
y = fct_rev(Response),
fill = assessment
)) +
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(
"Less favourable" = bg_pink,
"Equivalent" = bg_ink_32,
"More favourable" = bg_accent
),
guide = "none"
) +
scale_x_continuous(
labels = percent_format(),
expand = expansion(mult = c(0, 0.16))
) +
facet_wrap(
~Comparison,
ncol = 1,
scales = "free_y"
) +
labs(
x = "% of respondents",
y = NULL
) +
theme(
panel.spacing.y = grid::unit(26, "pt")
)The most frequent joint perception combines equally harmful environmental impact with a similar lifespan (36.0%). Only 16.2% simultaneously perceive fast tech as more harmful and shorter-lived than more expensive alternatives.
Durability and environmental judgements overlap only partially.
q22_joint_summary |>
ggplot(aes(
x = Lifespan,
y = Environmental_impact,
fill = pct
)) +
geom_tile(
colour = bg_surface,
linewidth = 1
) +
geom_text(
aes(label = percent(pct, accuracy = 0.1)),
colour = bg_ink,
size = bg_size_label / .pt
) +
scale_fill_bg_c(
palette = "seq",
labels = percent_format(),
name = "% of respondents"
) +
scale_x_discrete(
labels = \(x) str_wrap(x, width = 18)
) +
scale_y_discrete(
labels = \(x) str_wrap(x, width = 18)
) +
labs(x = "Perceived lifespan", y = "Perceived environmental impact") +
theme(
panel.grid = element_blank(),
legend.position = "top"
)q22_joint_summary |>
mutate(
Environmental_impact_flow = factor(
str_replace_all(
as.character(Environmental_impact),
" ",
"\n"
),
levels = str_replace_all(
environment_comparison_levels,
" ",
"\n"
)
),
Lifespan_flow = factor(
str_replace_all(
as.character(Lifespan),
" ",
"\n"
),
levels = str_replace_all(
lifespan_comparison_levels,
" ",
"\n"
)
)
) |>
ggplot(
aes(
axis1 = Environmental_impact_flow,
axis2 = Lifespan_flow,
y = weighted_n
)
) +
ggalluvial::geom_alluvium(
aes(fill = Environmental_impact_flow),
width = 0.18,
alpha = 0.45,
knot.pos = 0.45
) +
ggalluvial::geom_stratum(
width = 0.18,
fill = bg_surface,
colour = bg_ink_32
) +
ggalluvial::stat_stratum(
geom = "text",
aes(label = after_stat(stratum)),
size = bg_size_label / .pt
) +
scale_fill_manual(
values = c(
"Less\nharmful" = bg_accent,
"Equally\nharmful" = bg_ink_32,
"More\nharmful" = bg_pink
),
guide = "none"
) +
scale_x_discrete(
limits = c("Environmental impact", "Lifespan"),
expand = expansion(mult = c(0.16, 0.16))
) +
scale_y_continuous(labels = NULL, breaks = NULL) +
labs(x = NULL, y = NULL) +
theme(panel.grid = element_blank())attitude_levels <- c(
"Completely unfavourable",
"Rather unfavourable",
"Neither favourable nor unfavourable",
"Rather favourable",
"Completely favourable"
)
attitude_summary <- summarise_response_distribution(
df,
"Attitude_buying",
attitude_levels
)
attitude_mean <- weighted_mean_safe(
df$Attitude_buying_recoded,
df$analysis_weight
)
pct_attitude_favourable <- weighted_mean_safe(
df$Attitude_buying_recoded >= 4,
df$analysis_weight
)
pct_attitude_unfavourable <- weighted_mean_safe(
df$Attitude_buying_recoded <= 2,
df$analysis_weight
)Q23a. Regarding buying small and inexpensive electronic devices, you are…
Attitudes towards buying fast tech are mainly neutral, with an average of 3.22 on a five-point scale. Overall, 36.8% are rather or completely favourable, compared with 17.3% who are rather or completely unfavourable.
attitude_summary |>
ggplot(aes(x = Response, 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.12))
) +
labs(x = NULL, y = "% of respondents") +
theme(
axis.text.x = element_text(angle = 25, hjust = 1)
)future_intention_summary <- summarise_response_distribution(
df,
"12months_Intentionbuy",
future_purchase_intention_levels
)
pct_intend_more <- future_intention_summary |>
filter(Response %in% c("Much more", "More")) |>
summarise(pct = sum(pct)) |>
pull(pct)
pct_intend_less <- future_intention_summary |>
filter(Response %in% c(
"Less", "Much less", "I intend to stop"
)) |>
summarise(pct = sum(pct)) |>
pull(pct)
pct_not_intend_reduce <- future_intention_summary |>
filter(Response %in% c(
"The same",
"More",
"Much more"
)) |>
summarise(pct = sum(pct)) |>
pull(pct)Q25. Over the next 12 months, do you intend to buy more, fewer or the same number of small and inexpensive electronic devices?
Most respondents (54.6%) expect to buy the same number of fast tech products during the next 12 months. About a tenth (9.3%) intend to buy more or much more, while 36.1% intend to buy less, much less or stop altogether.
Put differently, 63.9% don’t intend to reduce their fast tech consumption, as they expect to buy the same number, more or much more over the next 12 months.
future_intention_summary |>
mutate(
response_type = if_else(
as.character(Response) == "I intend to stop",
"Stop",
"Other responses"
),
Response = factor(
as.character(Response),
levels = future_purchase_intention_levels
)
) |>
ggplot(aes(
x = Response,
y = pct,
fill = response_type
)) +
geom_col(width = bg_bar_width) +
geom_text(
aes(label = percent(pct, accuracy = 0.1)),
vjust = -0.4,
size = bg_size_label / .pt
) +
scale_fill_manual(
values = c(
"Other responses" = bg_accent,
"Stop" = bg_ink_32
),
guide = "none"
) +
scale_y_continuous(
labels = percent_format(),
expand = expansion(mult = c(0, 0.12))
) +
labs(
x = NULL,
y = "% of respondents"
) +
theme(
axis.text.x = element_text(
angle = 25,
hjust = 1
)
)agreement_levels <- c(
"I completely disagree",
"I disagree",
"I neither agree nor disagree",
"I agree",
"I completely agree"
)
consumer_view_summary <- summarise_response_distribution(
df,
"Consumers should buy fewer",
agreement_levels
)
pct_consumers_agree <- weighted_mean_safe(
df[["Consumers should buy fewer_recoded"]] >= 4,
df$analysis_weight
)
pct_consumers_disagree <- weighted_mean_safe(
df[["Consumers should buy fewer_recoded"]] <= 2,
df$analysis_weight
)Q26a. What do you think about the following statement? “Consumers should buy fewer small and inexpensive electronic devices.”
A short majority of respondents don’t have a strong opinion on the matter, and 40.8% agree or completely agree that consumers should buy fewer devices. Only 16.6% disagree or completely disagree.
consumer_view_summary |>
ggplot(aes(x = Response, 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.12))
) +
labs(x = NULL, y = "% of respondents") +
theme(
axis.text.x = element_text(angle = 25, hjust = 1)
)government_view_summary <- summarise_response_distribution(
df,
"Governments should more strictly regulate",
agreement_levels
)
pct_government_agree <- weighted_mean_safe(
df[["Governments should more strictly regulate_recoded"]] >= 4,
df$analysis_weight
)
pct_government_disagree <- weighted_mean_safe(
df[["Governments should more strictly regulate_recoded"]] <= 2,
df$analysis_weight
)Q26b. What do you think about the following statement? “Governments should more strictly regulate the sale of small and inexpensive electronic devices.”
Opinions regarding stricter government regulation are divided. 38.5% agree or completely agree, compared with 25.1% who disagree or completely disagree. The remaining respondents remain neutral.
government_view_summary |>
ggplot(aes(x = Response, 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.12))
) +
labs(x = NULL, y = "% of respondents") +
theme(
axis.text.x = element_text(angle = 25, hjust = 1)
)platform_awareness_levels <- c(
"Yes, I knew this",
"I heard of it but didn’t know the details",
"No, I didn’t know this"
)
platform_awareness_summary <- df |>
filter(!is.na(`Online plateforms obligations`)) |>
group_by(Response = `Online plateforms obligations`) |>
summarise(
n = n(),
weighted_n = sum(analysis_weight),
.groups = "drop"
) |>
mutate(
Response = factor(
Response,
levels = platform_awareness_levels
),
pct = weighted_n / sum(weighted_n)
) |>
arrange(Response)Q27. Did you know that online platforms selling electronic devices are legally required to contribute financially to the collection and recycling of electronic waste?
Only 29.1% knew about the requirement, while 13.8% had heard of it without knowing the details. More than half (57.1%) were unaware.
platform_awareness_summary |>
mutate(Response_plot = str_wrap(as.character(Response), 38)) |>
ggplot(aes(
x = pct,
y = fct_reorder(Response_plot, pct)
)) +
geom_col(width = bg_bar_width, fill = bg_accent) +
geom_text(
aes(label = percent(pct, accuracy = 0.1)),
hjust = -0.15,
size = bg_size_label / .pt
) +
scale_x_continuous(
labels = percent_format(),
expand = expansion(mult = c(0, 0.16))
) +
labs(x = "% of respondents", y = NULL)electronic_awareness_col <- names(df)[
str_detect(
names(df),
"^Before taking this questionnaire, were you aware"
)
]
electronic_awareness_summary <- df |>
transmute(
Response = .data[[electronic_awareness_col]],
analysis_weight
) |>
filter(!is.na(Response)) |>
group_by(Response) |>
summarise(
n = n(),
weighted_n = sum(analysis_weight),
.groups = "drop"
) |>
mutate(
Response = factor(Response, levels = c("Yes", "No")),
pct = weighted_n / sum(weighted_n)
) |>
arrange(Response)Q28. Before taking this questionnaire, were you aware that these small and inexpensive electronic devices contain electronic parts?
Only 17.3% were not aware that fast tech devices contain electronic parts, before completing the questionnaire.
electronic_awareness_summary |>
ggplot(aes(x = Response, 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.12))
) +
labs(x = NULL, y = "% of respondents")@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}
}
---
title: "Descriptive Statistical Analyses"
subtitle: "WEEE Forum Fast-Tech Consumer Study"
description: |
A multi-country study of fast tech purchasing, use and end-of-life behaviours among European consumers.
---
```{r}
#| label: setup
#| cache: false
source("R/fast-tech-shared.R")
```
::: {.executive-summary}
## Executive summary {.unnumbered}
This report presents descriptive findings from **`r format_count(n_participants)` respondents across `r n_countries` European countries**.
- **Fast tech is widespread.** Charging and lighting devices are present in `r format_percent(headline_household_charging_pct)` of surveyed households, while `r format_percent(headline_recent_purchase_pct)` of respondents bought at least one fast tech item during the previous 12 months (excluding e-vapes).
- **Purchase does not always translate into lasting use.** Among recent buyers, `r format_percent(headline_still_use_two_five_pct)` report that two to five purchased items remain in use. *`r headline_top_stopping_reason`* is the most frequently reported reason for stopping use.
- **End-of-life pathways.** Keeping devices at home and taking them to a recycling centre are the two most common individual responses. Disposal in household or plastic bin remains frequent, not necessarily ill-intentionned.
- **Durability offers a potential lever.** `r format_percent(headline_willing_pay_more_pct)` of previous buyers say they would pay more for at least some longer-lasting alternatives, although `r format_percent(headline_not_reduce_pct)` do not currently intend to reduce their fast tech purchases.
- **Attitudes** are favourable regarding fast tech buying and consumption.
:::
# Introduction
## Context
Small and inexpensive electronic devices have become increasingly visible and easy to purchase, particularly through online marketplaces. Although these products can fulfill practical needs, their low price, limited perceived value and sometimes short period of use may encourage frequent purchasing, accumulation at home and inappropriate disposal. These patterns raise environmental, social and political questions, about resource consumption, electronic-waste prevention and the responsibilities of consumers, producers, retailers and online platforms.
The WEEE Forum and its participating members commissioned a European consumer study for International E-Waste Day 2026. The main objective is to examine fast tech consumption, such as ownership and purchasing, end-of-life decisions, motivations and influences. A second objective is to identify behavioural patterns and knowledge gaps that can feed consumer communication, collection strategies and policy recommendations.
The study covers `r format_count(n_participants)` respondents across `r n_countries` European countries. Results are post-stratified to the age, gender and country distribution of the combined population aged 18–99. Weighting improves alignment on these observed characteristics but does not eliminate possible panel-selection, coverage or measurement bias. Comparisons therefore remain descriptive rather than causal.
The survey design, fieldwork, sample composition, weighting and data-processing procedures are documented in the [methodology report](methodology.qmd).
## Research Questions
The main research questions are:
1. **Fast tech consumption**\
How widespread is fast tech ownership and purchasing, which product categories are most commonly acquired, and how many devices are bought and stored at home?
2. **Drivers of purchasing behaviour**\
Which factors are associated with fast tech purchasing and future buying intentions?
3. **Use and end-of-life pathways**\
What happens to fast tech devices after purchase? How many remain in use, why do consumers stop using them? To what extent are unused devices stored, reused, donated, sold, recycled or discarded through inappropriate waste streams?
4. **Levers for more sustainable behaviour**\
Could greater durability, willingness to pay more, different replacement choices or improved collection convenience encourage consumers to reduce fast tech purchases and choose more sustainable alternatives?
5. **Knowledge and policy relevance**\
How aware are consumers that fast tech products contain electronic components and that online platforms may have financial obligations for electronic-waste collection and recycling? How strongly do consumers support reduced consumption and stricter regulation about electronic waste?
# Ownership
```{r}
#| label: detention-data
household_cols <- c(
"Household_Charging & lighting devices",
"Household_High-tech",
"Household_Gadgets & lifestyle items",
"Household_E-vapes"
)
band_levels <- c("0", "1", "2 to 5", "6 to 9", "10 to 19", "20+")
detention_long <- df |>
select(analysis_weight, all_of(household_cols)) |>
pivot_longer(
cols = all_of(household_cols),
names_to = "Category",
values_to = "Band"
) |>
mutate(
Category = str_remove(Category, "Household_"),
Band = factor(Band, levels = band_levels)
)
# Ownership rates by category
detention_ownership <- detention_long |>
group_by(Category) |>
summarise(
pct = weighted_mean_safe(Band != "0", analysis_weight),
.groups = "drop"
)
format_ownership_percent <- function(cat) percent(
detention_ownership$pct[detention_ownership$Category == cat],
accuracy = 0.1
)
# Combined quantities across the three non-vape categories.
# Since Q4 records ranges rather than exact counts, each respondent's combined
# quantity is represented by a minimum and a maximum.
household_non_vape_cols <- household_cols[
household_cols != "Household_E-vapes"
]
household_band_min <- c(
"0" = 0,
"1" = 1,
"2 to 5" = 2,
"6 to 9" = 6,
"10 to 19" = 10,
"20+" = 20
)
household_band_max <- c(
"0" = 0,
"1" = 1,
"2 to 5" = 5,
"6 to 9" = 9,
"10 to 19" = 19,
"20+" = Inf
)
detention_combined_levels <- c(
"No item",
"Exactly 1 item",
"Definitely 2 to 5 items",
"Could be 2 to 5 or 6+ items",
"Definitely 6 or more items"
)
detention_combined <- df |>
transmute(
analysis_weight,
across(
all_of(household_non_vape_cols),
as.character
)
) |>
mutate(
total_min = rowSums(
across(
all_of(household_non_vape_cols),
\(x) unname(household_band_min[x])
)
),
total_max = rowSums(
across(
all_of(household_non_vape_cols),
\(x) unname(household_band_max[x])
)
),
Combined_total = case_when(
total_max == 0 ~ "No item",
total_min == 1 & total_max == 1 ~ "Exactly 1 item",
total_min >= 2 & total_max <= 5 ~ "Definitely 2 to 5 items",
total_min > 5 ~ "Definitely 6 or more items",
TRUE ~ "Could be 2 to 5 or 6+ items"
),
Combined_total = factor(
Combined_total,
levels = detention_combined_levels
)
)
detention_combined_summary <- detention_combined |>
group_by(Combined_total, .drop = FALSE) |>
summarise(
n = n(),
weighted_n = sum(analysis_weight),
.groups = "drop"
) |>
mutate(pct = weighted_n / sum(weighted_n)) |>
arrange(Combined_total)
detention_combined_pct <- setNames(
detention_combined_summary$pct,
as.character(detention_combined_summary$Combined_total)
)
pct_own_non_vape <- 1 - detention_combined_pct[["No item"]]
pct_definitely_six_plus <- detention_combined_pct[[
"Definitely 6 or more items"
]]
pct_definitely_two_five <- detention_combined_pct[[
"Definitely 2 to 5 items"
]]
pct_possible_two_five <- pct_definitely_two_five +
detention_combined_pct[["Could be 2 to 5 or 6+ items"]]
```
## Items owned at home, by category
::: question
**Q4.** How many of the following items are currently in your household (regardless of who bought them or when)?
:::
Fast tech items are present in the vast majority of surveyed households. **Charging and lighting devices** lead with **`r format_ownership_percent("Charging & lighting devices")` of respondents owning at least one**, followed by **high-tech items (`r format_ownership_percent("High-tech")`)** and **gadgets & lifestyle items (`r format_ownership_percent("Gadgets & lifestyle items")`)**. E-vapes are considerably less widespread, owned by `r format_ownership_percent("E-vapes")` of the sample, reflecting a different usage.
```{r}
#| label: fig-detention-ownership
#| fig-cap: "Share of respondents with at least one fast tech item at home, by category"
detention_long |>
group_by(Category) |>
summarise(
pct = weighted_mean_safe(Band != "0", analysis_weight),
.groups = "drop"
) |>
mutate(category_type = if_else(Category == "E-vapes", "E-vapes", "Other categories")) |>
ggplot(aes(x = reorder(Category, pct), y = pct, fill = category_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("Other categories" = bg_accent,"E-vapes" = bg_ink_32), guide = "none") +
scale_y_continuous(labels = percent_format(), expand = expansion(mult = c(0, 0.12))) +
coord_flip() +
labs(x = NULL, y = "% respondents owning at least one item")
```
## Quantity owned
The quantity distributions differ markedly by category. E-vapes have the highest share of non-ownership, while the modal quantity among the three other categories is generally between two and five items.
```{r}
#| label: fig-detention-quantity-distribution
#| fig-cap: "Distribution of quantities owned at home, by category"
detention_long |>
group_by(Category, Band, .drop = FALSE) |>
summarise(
n = n(),
weighted_n = sum(analysis_weight),
.groups = "drop_last"
) |>
mutate(
pct = weighted_n / sum(weighted_n),
band_type = if_else(
as.character(Band) == "0",
"No item",
"At least one item"
)
) |>
ungroup() |>
ggplot(
aes(
x = Band,
y = pct,
fill = band_type
)
) +
geom_col(
width = bg_bar_width
) +
geom_text(
aes(label = percent(pct, accuracy = 0.1)),
vjust = -0.4,
size = bg_size_label / .pt
) +
scale_fill_manual(
values = c(
"No item" = bg_ink_32,
"At least one item" = bg_accent
),
guide = "none"
) +
scale_y_continuous(
labels = percent_format(),
expand = expansion(mult = c(0, 0.12))
) +
facet_wrap(
~Category,
ncol = 2
) +
labs(
x = "Number of items",
y = NULL
) +
theme(
axis.text.x = element_text(
angle = 30,
hjust = 1
),
panel.spacing.y = grid::unit(28, "pt")
)
```
### Combined quantity across categories, excluding e-vapes
Across charging and lighting devices, high-tech products, and gadgets and lifestyle items, **`r format_percent(pct_own_non_vape)` of respondents own at least one item**. At least **`r format_percent(pct_definitely_six_plus)` definitely own six or more items**.
> **Note:** Because the questionnaire records a range for each category, the exact proportion owning two to five items in total cannot be identified. It lies between **`r format_percent(pct_definitely_two_five)`**, who are certainly in this range, and **`r format_percent(pct_possible_two_five)`**, which additionally includes respondents whose category ranges could sum either to two to five or to six or more items.
```{r}
#| label: fig-detention-quantity-combined
#| fig-cap: "Combined quantity of fast tech items owned across non-vape categories"
detention_combined_summary |>
mutate(
total_type = case_when(
Combined_total == "No item" ~ "None",
Combined_total == "Could be 2 to 5 or 6+ items" ~ "Range uncertainty",
TRUE ~ "Classified total"
)
) |>
ggplot(aes(
x = pct,
y = fct_rev(Combined_total),
fill = total_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(
"None" = bg_ink_32,
"Range uncertainty" = bg_blue_50,
"Classified total" = bg_accent
),
guide = "none"
) +
scale_x_continuous(
labels = percent_format(),
expand = expansion(mult = c(0, 0.16))
) +
labs(
x = "% of respondents",
y = NULL
)
```
## Ownership by socio-demographic characteristics
```{r}
#| label: detention-sociodemo-data
detention_sociodemo_data <- df |>
transmute(
Age_group = as.character(Age_recoded_1),
Gender_group = recode(
as.character(Gender),
"98" = "No answer"
),
Employment_group = as.character(Employment),
Household_size = as.numeric(Nb_household),
analysis_weight,
detention_any_non_vape = if_any(
all_of(household_non_vape_cols),
~ as.character(.x) != "0"
)
)
summarise_ownership_dimension <- function(
variable,
dimension,
levels
) {
detention_sociodemo_data |>
transmute(
Group = as.character(
.data[[variable]]
),
analysis_weight,
outcome = as.integer(
detention_any_non_vape
)
) |>
filter(
!is.na(outcome),
Group %in% levels
) |>
group_by(Group) |>
summarise(
n = n(),
pct = weighted_mean_safe(outcome, analysis_weight),
.groups = "drop"
) |>
mutate(
Dimension = dimension,
Group = factor(
Group,
levels = levels
)
)
}
detention_overall <- weighted_mean_safe(
detention_sociodemo_data$detention_any_non_vape,
detention_sociodemo_data$analysis_weight
)
detention_desired_rows <- c(
paste(
"Age",
sociodemographic_age_levels,
sep = "___"
),
paste(
"Gender",
sociodemographic_gender_levels,
sep = "___"
),
paste(
"Employment",
sociodemographic_employment_levels,
sep = "___"
)
)
detention_sociodemo_summary <- bind_rows(
summarise_ownership_dimension(
"Age_group",
"Age",
sociodemographic_age_levels
),
summarise_ownership_dimension(
"Gender_group",
"Gender",
sociodemographic_gender_levels
),
summarise_ownership_dimension(
"Employment_group",
"Employment",
sociodemographic_employment_levels
)
) |>
mutate(
Dimension = factor(
Dimension,
levels = c(
"Age",
"Gender",
"Employment"
)
),
Group_plot = paste(
Dimension,
as.character(Group),
sep = "___"
),
Group_plot = factor(
Group_plot,
levels = rev(
detention_desired_rows
)
),
overall = detention_overall,
comparison = if_else(
pct >= overall,
"At or above overall",
"Below overall"
)
)
detention_household_model_data <-
detention_sociodemo_data |>
transmute(
Household_size,
analysis_weight,
outcome = as.integer(
detention_any_non_vape
)
) |>
drop_na()
detention_household_design <- survey::svydesign(
ids = ~1,
weights = ~analysis_weight,
data = detention_household_model_data
)
detention_household_model <- survey::svyglm(
outcome ~ Household_size,
design = detention_household_design,
family = quasibinomial()
)
detention_household_grid <- tibble(
Household_size = seq(
min(
detention_household_model_data$
Household_size
),
max(
detention_household_model_data$
Household_size
),
length.out = 100
)
)
detention_household_prediction <- predict(
detention_household_model,
newdata = detention_household_grid,
type = "link"
)
detention_household_prediction_fit <- as.numeric(
detention_household_prediction
)
detention_household_prediction_se <- as.numeric(
survey::SE(detention_household_prediction)
)
detention_household_curve <-
detention_household_grid |>
mutate(
pct = plogis(
detention_household_prediction_fit
),
lower = plogis(
detention_household_prediction_fit -
1.96 *
detention_household_prediction_se
),
upper = plogis(
detention_household_prediction_fit +
1.96 *
detention_household_prediction_se
)
)
detention_household_observed <-
detention_household_model_data |>
group_by(Household_size) |>
summarise(
n = n(),
pct = weighted_mean_safe(outcome, analysis_weight),
.groups = "drop"
)
detention_age_young <-
detention_sociodemo_summary |>
filter(
Dimension == "Age",
Group == "18-29"
) |>
pull(pct)
detention_age_old <-
detention_sociodemo_summary |>
filter(
Dimension == "Age",
Group == "65-99"
) |>
pull(pct)
detention_employment_high <-
detention_sociodemo_summary |>
filter(Dimension == "Employment") |>
slice_max(
pct,
n = 1,
with_ties = FALSE
)
detention_employment_low <-
detention_sociodemo_summary |>
filter(Dimension == "Employment") |>
slice_min(
pct,
n = 1,
with_ties = FALSE
)
```
Ownership of at least one fast tech item (excluding e-vapes) is high across all socio-demographic groups. It ranges from **`r format_percent(detention_age_young)` among respondents aged 18–29** to **`r format_percent(detention_age_old)` among those aged 65–99**. By employment status, it is highest among `r tolower(as.character(detention_employment_high$Group))` respondents (`r format_percent(detention_employment_high$pct)`) and lowest among `r tolower(as.character(detention_employment_low$Group))` respondents (`r format_percent(detention_employment_low$pct)`).
Basically, it means that **almost all 18-39 years old** and **almost all students detain at least one fast tech item**.
> **Note:** These are population-weighted, unadjusted descriptive comparisons. Gender categories with non-substantive answers and employment respondents who preferred not to answer are excluded.
```{r}
#| label: fig-detention-sociodemo
#| fig-cap: "Ownership of at least one non-vape fast tech item, by socio-demographic group"
#| fig-height: 8
detention_sociodemo_summary |>
ggplot(aes(
x = pct,
y = Group_plot,
colour = comparison
)) +
geom_vline(
xintercept =
detention_sociodemo_summary$
overall[[1]],
colour = bg_ink_32,
linewidth = bg_lw_hairline,
linetype = "dashed"
) +
geom_segment(
aes(
x = overall,
xend = pct,
yend = Group_plot
),
colour = bg_ink_32,
linewidth = bg_lw_line
) +
geom_point(size = 3) +
geom_text(
aes(
label = percent(
pct,
accuracy = 0.1
)
),
hjust = -0.35,
colour = bg_ink,
size = bg_size_label / .pt
) +
scale_colour_manual(
values = c(
"At or above overall" = bg_accent,
"Below overall" = bg_blue
),
guide = "none"
) +
scale_x_continuous(
labels = percent_format(),
limits = c(0, 1),
expand = expansion(
mult = c(0, 0.06)
)
) +
scale_y_discrete(
labels = \(x) {
str_remove(x, "^.*___")
}
) +
facet_grid(
rows = vars(Dimension),
scales = "free_y",
space = "free_y"
) +
labs(
x = "% owning at least one item",
y = NULL
) +
theme(
strip.text.y = element_text(
angle = 0
)
)
```
Household size is treated as a continuous predictor. The curve below shows the population-weighted estimated probability of ownership, with the weighted observed rate for each household size overlaid.
```{r}
#| label: fig-detention-household-size
#| fig-cap: "Ownership of non-vape fast tech by household size. The bigger the point, the more respondents."
ggplot(
detention_household_curve,
aes(x = Household_size, y = pct)
) +
geom_ribbon(
aes(ymin = lower, ymax = upper),
fill = bg_accent_20,
alpha = bg_alpha_mute
) +
geom_line(
colour = bg_accent,
linewidth = bg_lw_line
) +
geom_point(
data = detention_household_observed,
colour = bg_ink,
aes(size = n)
) +
scale_size_continuous(
name = "N",
range = c(2, 5)
) +
scale_x_continuous(
breaks = 1:10
) +
scale_y_continuous(
labels = percent_format(),
limits = c(0, 1),
expand = expansion(
mult = c(0, 0.04)
)
) +
labs(
x = "Household size",
y = "Estimated probability of ownership"
)
```
------------------------------------------------------------------------
# Buying Behaviour
```{r}
#| label: buying-behaviour-data
buying_band_levels <- c(
"0", "1", "2 to 5", "6 to 9", "10 to 19", "20+"
)
n_total <- nrow(df)
n_ever_bought <- sum(df$Buyer == "Buyer", na.rm = TRUE)
pct_ever_bought <- weighted_mean_safe(
df$Buyer == "Buyer",
df$analysis_weight
)
n_recent_buyers <- sum(df$Buy_12months == "Buyer", na.rm = TRUE)
pct_recent_buyers <- weighted_mean_safe(
df$Buy_12months == "Buyer",
df$analysis_weight
)
```
Non-buyers are respondents who declared never having bought any fast tech device.
## Buyers demographics
```{r}
#| label: buyer-demographics-data
buyer_demographics_data <- df |>
transmute(
Buyer_group = recode(
Buyer,
"Buyer" = "Buyers",
"Non buyer" = "Non-buyers"
),
Age = as.numeric(Age),
Gender = as.character(Gender),
Country,
analysis_weight,
Income = coalesce(
Income_Norway,
Income_Romania,
Income_Poland,
Income_Switzerland,
Income_UK,
Income_Euro
)
) |>
group_by(Country) |>
mutate(
income_lower = income_lower_bound(Income),
income_bracket_position =
assign_income_bracket_position(
Country,
income_lower
),
income_n_brackets = n_distinct(
income_lower,
na.rm = TRUE
),
income_eur_equivalent = case_when(
is.na(income_lower) ~ NA_real_,
Country == "Switzerland" &
income_bracket_position == income_n_brackets ~ 135000,
TRUE ~ 5000 +
(income_bracket_position - 1) * 10000
)
) |>
ungroup()
buyer_demographics_summary <- buyer_demographics_data |>
filter(!is.na(Buyer_group)) |>
group_by(Buyer_group) |>
summarise(
n = n(),
age_mean = weighted_mean_safe(Age, analysis_weight),
age_sd = weighted_sd_safe(Age, analysis_weight),
income_median = weighted_quantile_safe(
income_eur_equivalent, analysis_weight, probs = 0.5
),
income_q1 = weighted_quantile_safe(
income_eur_equivalent, analysis_weight, probs = 0.25
),
income_q3 = weighted_quantile_safe(
income_eur_equivalent, analysis_weight, probs = 0.75
),
.groups = "drop"
)
buyer_gender_summary <- buyer_demographics_data |>
filter(
Gender %in% c(
"Female",
"Male",
"Non-binary"
)
) |>
group_by(Buyer_group, Gender) |>
summarise(
n = n(),
weighted_n = sum(analysis_weight),
.groups = "drop_last"
) |>
mutate(pct = weighted_n / sum(weighted_n)) |>
ungroup()
buyer_demographics_design <- survey::svydesign(
ids = ~1,
weights = ~analysis_weight,
data = buyer_demographics_data |>
mutate(Buyer_binary = as.integer(Buyer_group == "Buyers"))
)
buyer_age_test <- survey::svyttest(
Age ~ Buyer_binary,
design = subset(
buyer_demographics_design,
!is.na(Age) & !is.na(Buyer_binary)
)
)
buyer_gender_test <- survey::svychisq(
~Buyer_group + Gender,
design = subset(
buyer_demographics_design,
Gender %in% c("Female", "Male")
),
statistic = "F"
)
buyer_age_gender_model_data <- buyer_demographics_data |>
filter(
!is.na(Age),
!is.na(Buyer_group),
Gender %in% c("Female", "Male")
) |>
mutate(
Buyer_binary = as.integer(Buyer_group == "Buyers"),
Gender = factor(Gender, levels = c("Female", "Male")),
Age_centered = Age - weighted_mean_safe(Age, analysis_weight)
)
buyer_age_gender_design <- survey::svydesign(
ids = ~1,
weights = ~analysis_weight,
data = buyer_age_gender_model_data
)
buyer_age_gender_model <- survey::svyglm(
Buyer_binary ~ Age_centered * Gender,
design = buyer_age_gender_design,
family = quasibinomial()
)
buyer_age_gender_interaction_test <- survey::regTermTest(
buyer_age_gender_model,
~Age_centered:Gender
)
buyer_age_gender_interaction_p <- as.numeric(
buyer_age_gender_interaction_test$p
)[1]
buyer_income_test <- survey::svyranktest(
income_eur_equivalent ~ Buyer_binary,
design = subset(
buyer_demographics_design,
!is.na(income_eur_equivalent) & !is.na(Buyer_binary)
),
test = "wilcoxon"
)
buyer_age_mean <- setNames(
buyer_demographics_summary$age_mean,
buyer_demographics_summary$Buyer_group
)
buyer_income_median <- setNames(
buyer_demographics_summary$income_median,
buyer_demographics_summary$Buyer_group
)
buyer_income_q1 <- setNames(
buyer_demographics_summary$income_q1,
buyer_demographics_summary$Buyer_group
)
buyer_income_q3 <- setNames(
buyer_demographics_summary$income_q3,
buyer_demographics_summary$Buyer_group
)
buyer_female_pct <- setNames(
buyer_gender_summary$pct[
buyer_gender_summary$Gender == "Female"
],
buyer_gender_summary$Buyer_group[
buyer_gender_summary$Gender == "Female"
]
)
buyer_group_colours <- c(
"Buyers" = bg_accent,
"Non-buyers" = bg_blue
)
buyer_age_gender_data <- buyer_demographics_data |>
filter(
!is.na(Age),
Gender %in% c(
"Female",
"Male"
)
) |>
mutate(
Buyer_group = factor(
Buyer_group,
levels = c(
"Buyers",
"Non-buyers"
)
),
group_y = case_when(
Buyer_group == "Buyers" ~ 1,
Buyer_group == "Non-buyers" ~ 2
),
gender_direction = if_else(
Gender == "Female",
1,
-1
),
box_y = group_y +
gender_direction * 0.13
)
buyer_age_axis_labels <- buyer_age_gender_data |>
count(Buyer_group, name = "n") |>
mutate(
axis_label = paste0(
Buyer_group,
"\nN = ",
format_count(n)
)
) |>
select(
Buyer_group,
axis_label
) |>
deframe()
buyer_age_gender_density <- buyer_age_gender_data |>
group_by(
Buyer_group,
Gender,
group_y,
gender_direction
) |>
group_modify(
\(.x, .y) {
density_estimate <- density(
.x$Age,
weights = .x$analysis_weight / sum(.x$analysis_weight),
from = 18,
to = 90,
n = 512
)
tibble(
Age = density_estimate$x,
density = density_estimate$y
)
}
) |>
ungroup() |>
mutate(
density_height =
density / max(density) * 0.38,
density_y = group_y +
gender_direction * density_height
)
buyer_age_gender_means <- buyer_age_gender_data |>
group_by(Buyer_group, Gender) |>
summarise(
Age = weighted_mean_safe(Age, analysis_weight),
box_y = first(box_y),
.groups = "drop"
)
```
Buyers are younger than non-buyers: their mean age is **`r number(buyer_age_mean[["Buyers"]], accuracy = 0.1)` years**, compared with **`r number(buyer_age_mean[["Non-buyers"]], accuracy = 0.1)` years** among non-buyers (`r format_p_value(buyer_age_test$p.value)`). Women account for `r format_percent(buyer_female_pct[["Buyers"]])` of buyers and `r format_percent(buyer_female_pct[["Non-buyers"]])` of non-buyers; buyer status also differs by gender (`r format_p_value(buyer_gender_test$p.value)`). The age gradient does `r if_else(buyer_age_gender_interaction_p < 0.05, "", "not ")`differ significantly between women and men (`r format_p_value(buyer_age_gender_interaction_p)`).
```{r}
#| label: fig-buyer-age
#| fig-cap: "Age distribution of buyers and non-buyers, by gender"
#| fig-height: 4.2
ggplot() +
geom_hline(
yintercept = c(1, 2),
colour = bg_ink_32,
linewidth = bg_lw_hairline
) +
geom_ribbon(
data = buyer_age_gender_density,
aes(
x = Age,
ymin = group_y,
ymax = density_y,
fill = Buyer_group,
alpha = Gender,
group = interaction(
Buyer_group,
Gender
)
),
colour = NA
) +
geom_boxplot(
data = buyer_age_gender_data,
aes(
x = Age,
y = box_y,
weight = analysis_weight,
group = interaction(
Buyer_group,
Gender
)
),
orientation = "y",
width = 0.09,
outlier.shape = NA,
fill = bg_surface,
colour = bg_ink,
alpha = 0.85,
linewidth = bg_lw_hairline
) +
geom_point(
data = buyer_age_gender_means,
aes(
x = Age,
y = box_y
),
shape = 21,
size = 2.8,
stroke = 0.7,
fill = bg_surface,
colour = bg_ink
) +
scale_fill_manual(
values = buyer_group_colours,
guide = "none"
) +
scale_alpha_manual(
name = NULL,
breaks = c(
"Female",
"Male"
),
labels = c(
"Women (above)",
"Men (below)"
),
values = c(
"Female" = 0.78,
"Male" = 0.34
),
guide = guide_legend(
override.aes = list(
fill = bg_accent,
colour = NA
)
)
) +
scale_x_continuous(
breaks = seq(0, 90, by = 10),
limits = c(0, 90),
expand = expansion(mult = c(0.01, 0.01))
) +
scale_y_continuous(
breaks = c(1, 2),
labels = c(
buyer_age_axis_labels[["Buyers"]],
buyer_age_axis_labels[["Non-buyers"]]
),
limits = c(0.55, 2.45),
expand = expansion(mult = c(0, 0))
) +
labs(
x = "Age",
y = NULL,
caption = str_wrap(
paste(
"Women: above centre line; men: below.",
"White circles: means; boxes: medians and IQRs."
),
width = 88
)
) +
theme(
panel.grid.major.y = element_blank(),
panel.grid.minor = element_blank(),
legend.position = "top"
)
```
The median approximate income bracket is **€`r number(buyer_income_median[["Buyers"]], scale = 0.001, suffix = "k", accuracy = 1)` in both groups**, but the buyers’ distribution is shifted towards higher brackets: its middle 50% ranges from €`r number(buyer_income_q1[["Buyers"]], scale = 0.001, suffix = "k", accuracy = 1)` to €`r number(buyer_income_q3[["Buyers"]], scale = 0.001, suffix = "k", accuracy = 1)`, compared with €`r number(buyer_income_q1[["Non-buyers"]], scale = 0.001, suffix = "k", accuracy = 1)` to €`r number(buyer_income_q3[["Non-buyers"]], scale = 0.001, suffix = "k", accuracy = 1)` among non-buyers (`r format_p_value(buyer_income_test$p.value)`). It means that, overall, buyers seem to have higher revenues.
## Ever bought fast tech
::: question
**Q5.** Have you ever bought small and inexpensive electronic devices, excluding e-vapes?
:::
Fast tech purchasing is widespread in the surveyed population. Overall, **`r format_count(n_ever_bought)` respondents (`r format_percent(pct_ever_bought)`) have bought fast tech at least once**, while `r format_count(n_total - n_ever_bought)` (`r format_percent(1 - pct_ever_bought)`) report never having bought these products.
```{r}
#| label: fig-ever-bought-fast-tech
#| fig-cap: "Respondents who have ever bought fast tech"
buyer_status <- df |>
filter(!is.na(Buyer)) |>
group_by(Buyer) |>
summarise(
n = n(),
weighted_n = sum(analysis_weight),
.groups = "drop"
) |>
mutate(
Status = recode(
Buyer,
"Buyer" = "Ever bought fast tech",
"Non buyer" = "Never bought fast tech"
),
pct = weighted_n / sum(weighted_n)
)
buyer_status |>
ggplot(aes(x = reorder(Status, 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.12))
) +
coord_flip() +
labs(x = NULL, y = "% of respondents")
```
## Purchased during the last 12 months
```{r}
#| label: recent-purchase-data
recent_purchase_long <- df |>
select(analysis_weight, all_of(recent_purchase_cols)) |>
pivot_longer(
cols = all_of(recent_purchase_cols),
names_to = "Category",
values_to = "Band"
) |>
mutate(
Category = str_remove(Category, "^Buy_12months_"),
Band = factor(
as.character(Band),
levels = buying_band_levels
)
)
recent_purchase_summary <- recent_purchase_long |>
group_by(Category) |>
summarise(
n_respondents = sum(!is.na(Band)),
n_bought = sum(Band != "0", na.rm = TRUE),
pct = weighted_mean_safe(Band != "0", analysis_weight),
.groups = "drop"
)
recent_purchase_combined_levels <- c(
"No purchase",
"Exactly 1 item",
"Definitely 2 to 5 items",
"Could be 2 to 5 or 6+ items",
"Definitely 6 or more items"
)
recent_purchase_combined <- df |>
transmute(
analysis_weight,
across(
all_of(recent_purchase_cols),
as.character
)
) |>
mutate(
total_min = rowSums(
across(
all_of(recent_purchase_cols),
\(x) unname(household_band_min[x])
)
),
total_max = rowSums(
across(
all_of(recent_purchase_cols),
\(x) unname(household_band_max[x])
)
),
Combined_total = case_when(
total_max == 0 ~ "No purchase",
total_min == 1 & total_max == 1 ~ "Exactly 1 item",
total_min >= 2 & total_max <= 5 ~ "Definitely 2 to 5 items",
total_min > 5 ~ "Definitely 6 or more items",
TRUE ~ "Could be 2 to 5 or 6+ items"
),
Combined_total = factor(
Combined_total,
levels = recent_purchase_combined_levels
)
)
recent_purchase_combined_summary <- recent_purchase_combined |>
group_by(Combined_total, .drop = FALSE) |>
summarise(
n = n(),
weighted_n = sum(analysis_weight),
.groups = "drop"
) |>
mutate(pct = weighted_n / sum(weighted_n)) |>
arrange(Combined_total)
recent_purchase_combined_pct <- setNames(
recent_purchase_combined_summary$pct,
as.character(recent_purchase_combined_summary$Combined_total)
)
pct_no_recent_purchase <- recent_purchase_combined_pct[["No purchase"]]
pct_exactly_one_recent_purchase <- recent_purchase_combined_pct[[
"Exactly 1 item"
]]
pct_definitely_six_plus_recent_purchase <- recent_purchase_combined_pct[[
"Definitely 6 or more items"
]]
pct_definitely_two_five_recent_purchase <- recent_purchase_combined_pct[[
"Definitely 2 to 5 items"
]]
pct_possible_two_five_recent_purchase <-
pct_definitely_two_five_recent_purchase +
recent_purchase_combined_pct[["Could be 2 to 5 or 6+ items"]]
```
::: question
**Q3.** How many of the following items did you personally buy, over the last 12 months?
:::
**`r format_count(n_recent_buyers)` respondents (`r format_percent(pct_recent_buyers)`)** purchased at least one fast tech item during the previous 12 months (August 2025 - July 2026).
Charging and lighting devices are most bought (`r format_percent(weighted_mean_safe(df[["Buy_12months_Charging & lighting devices"]] != "0", df$analysis_weight))` of respondents), while gadgets and lifestyle items (`r format_percent(weighted_mean_safe(df[["Buy_12months_Gadgets & lifestyle items"]] != "0", df$analysis_weight))`) and high-tech products (`r format_percent(weighted_mean_safe(df[["Buy_12months_High-tech"]] != "0", df$analysis_weight))`) were bought by a little over half of the respondents.
> **Note:** since e-vapes are banned from most european countries, we didn't ask the question about this category
```{r}
#| label: fig-purchased-last-12months
#| fig-cap: "Share of respondents who purchased fast tech during the last 12 months, by category"
recent_purchase_summary |>
ggplot(aes(x = reorder(Category, 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(),
limits = c(0, NA),
expand = expansion(mult = c(0, 0.12))
) +
coord_flip() +
labs(
x = NULL,
y = "% of all respondents"
)
```
## Quantity purchased
Charging and lighting devices have the highest overall purchasing rate, with **`r format_percent(headline_charging_two_five_pct)` of respondents having bought 2 to 5 items** during the past year.
```{r}
#| label: fig-buying-quantity-distribution
#| fig-cap: "Number of fast tech items purchased during the last 12 months, by category"
recent_purchase_long |>
group_by(Category, Band, .drop = FALSE) |>
summarise(
n = n(),
weighted_n = sum(analysis_weight),
.groups = "drop_last"
) |>
mutate(
pct = weighted_n / sum(weighted_n),
band_type = if_else(
as.character(Band) == "0",
"No purchase",
"At least one purchase"
)
) |>
ungroup() |>
ggplot(
aes(
x = Band,
y = pct,
fill = band_type
)
) +
geom_col(width = bg_bar_width) +
geom_text(
aes(
label = if_else(
pct >= 0.02,
percent(pct, accuracy = 0.1),
""
)
),
vjust = -0.4,
size = bg_size_label / .pt
) +
scale_fill_manual(
values = c(
"No purchase" = bg_ink_32,
"At least one purchase" = bg_accent
),
guide = "none"
) +
scale_y_continuous(
labels = percent_format(),
expand = expansion(mult = c(0, 0.13))
) +
facet_wrap(
~Category,
ncol = 1
) +
labs(
x = "Number of items purchased",
y = "% of respondents"
) +
theme(
axis.text.x = element_text(
angle = 30,
hjust = 1
),
panel.spacing.y = grid::unit(32, "pt")
)
```
### Combined quantity across fast tech categories
About **`r format_percent(1 - pct_no_recent_purchase)` of respondents bought at least one fast tech item during the last 12 months** (excluding e-vapes). `r format_percent(pct_exactly_one_recent_purchase)` bought exactly one item, while at least `r format_percent(pct_definitely_six_plus_recent_purchase)` bought six or more.
The exact share buying two to five items in total lies between **`r format_percent(pct_definitely_two_five_recent_purchase)`** and **`r format_percent(pct_possible_two_five_recent_purchase)`**, depending on the exact counts within the ranges selected for each category.
> **Note:** Q3 uses quantity ranges for each category. Combined totals therefore preserve the resulting uncertainty rather than imputing an exact number within each range.
```{r}
#| label: fig-buying-quantity-combined
#| fig-cap: "Combined quantity of fast tech items purchased during the last 12 months"
recent_purchase_combined_summary |>
mutate(
total_type = case_when(
Combined_total == "No purchase" ~ "None",
Combined_total == "Could be 2 to 5 or 6+ items" ~ "Range uncertainty",
TRUE ~ "Classified total"
)
) |>
ggplot(aes(
x = pct,
y = fct_rev(Combined_total),
fill = total_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(
"None" = bg_ink_32,
"Range uncertainty" = bg_blue_50,
"Classified total" = bg_accent
),
guide = "none"
) +
scale_x_continuous(
labels = percent_format(),
expand = expansion(mult = c(0, 0.16))
) +
labs(
x = "% of respondents",
y = NULL
)
```
## Buying intention, by item category
```{r}
#| label: buying-intention-data
intention_cols <- c(
"Charging & lighting devices_Intend to buy",
"High-tech_Intend to buy",
"Gadgets & lifestyle items_Intend to buy"
)
intention_summary <- df |>
select(analysis_weight, all_of(intention_cols)) |>
pivot_longer(
cols = all_of(intention_cols),
names_to = "Category",
values_to = "Intention"
) |>
filter(!is.na(Intention)) |>
mutate(
Category = str_remove(Category, "_Intend to buy$")
) |>
group_by(Category) |>
summarise(
n_presented = n(),
n_intended = sum(Intention == "Intended"),
pct = weighted_mean_safe(Intention == "Intended", analysis_weight),
.groups = "drop"
)
intention_percent_by_category <- setNames(
intention_summary$pct,
intention_summary$Category
)
```
::: question
**Q8/Q9.** Let’s talk about the most recent \[Category A/B\] you bought. **Q8a/Q9a.** Did you intend to buy it?
:::
Buying intentions are high for all three product categories. Among respondents to whom the category was presented, `r format_percent(intention_percent_by_category[["Charging & lighting devices"]])` intended to buy charging and lighting devices, `r format_percent(intention_percent_by_category[["High-tech"]])` intended to buy high-tech products, and `r format_percent(intention_percent_by_category[["Gadgets & lifestyle items"]])` intended to buy gadgets and lifestyle items.
```{r}
#| label: fig-buying-intention-category
#| fig-cap: "Intention to buy fast tech items"
intention_summary |>
ggplot(aes(x = reorder(Category, 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(),
limits = c(0, 1),
expand = expansion(mult = c(0, 0.08))
) +
coord_flip() +
labs(
x = NULL,
y = "% intending to buy"
)
```
## Buying reasons
```{r}
#| label: item-buying-reasons-data
item_categories <- c(
"Charging & lighting devices",
"High-tech",
"Gadgets & lifestyle items"
)
item_reason_suffixes <- c(
"For work, study or everyday use",
"As a temporary replacement",
"I wanted a newer version",
"As a spare device",
"I bought it even though I didn't really need it",
"It was a gift for someone else",
"There was no other product / no other choice",
"Other"
)
item_reason_cols <- unlist(
lapply(
item_categories,
\(category) paste0(category, "_", item_reason_suffixes)
),
use.names = FALSE
)
item_reason_summary <- df |>
select(analysis_weight, all_of(item_reason_cols)) |>
pivot_longer(
cols = all_of(item_reason_cols),
names_to = "Variable",
values_to = "Value"
) |>
filter(!is.na(Value)) |>
mutate(
Category = str_extract(Variable, "^[^_]+"),
Reason = str_remove(Variable, "^[^_]+_"),
selected = is_selected(Value)
) |>
group_by(Category, Reason) |>
summarise(
n = sum(selected),
denominator = n(),
pct = weighted_mean_safe(selected, analysis_weight),
.groups = "drop"
) |>
mutate(
Reason_plot = str_wrap(Reason, width = 36)
)
item_reason_combined_summary <- df |>
mutate(respondent_id = row_number()) |>
select(
respondent_id,
analysis_weight,
all_of(item_reason_cols)
) |>
pivot_longer(
cols = all_of(item_reason_cols),
names_to = "Variable",
values_to = "Value"
) |>
mutate(
Reason = str_remove(
Variable,
"^[^_]+_"
),
presented = !is.na(Value),
selected = is_selected(Value)
) |>
group_by(
respondent_id,
Reason
) |>
summarise(
analysis_weight = first(analysis_weight),
presented = any(presented),
selected = any(selected),
.groups = "drop"
) |>
filter(presented) |>
group_by(Reason) |>
summarise(
n = sum(selected),
denominator = n(),
pct = weighted_mean_safe(selected, analysis_weight),
.groups = "drop"
) |>
arrange(desc(pct)) |>
mutate(
Reason_plot = str_wrap(
Reason,
width = 42
)
)
item_reason_combined_pct <- setNames(
item_reason_combined_summary$pct,
item_reason_combined_summary$Reason
)
format_item_reason_percent <- function(
category,
reason
) {
format_percent(
item_reason_summary$pct[
item_reason_summary$Category == category &
item_reason_summary$Reason == reason
]
)
}
```
::: question
**Q8b/Q9b.** Why did you buy it?
:::
Reasons differ by category, even though **fast tech items are mostly bought for use, as a replacement or as a spare device**. High-tech items are more often reported as purchases motivated by wanting a newer version (`r format_item_reason_percent("High-tech", "I wanted a newer version")`), while gadgets and lifestyle items are more often reported as purchases made without a real need (`r format_item_reason_percent("Gadgets & lifestyle items", "I bought it even though I didn't really need it")`).
> **Note:** these were multiple-response questions, so respondents could select more than one reason and percentages do not sum to 100%.
```{r}
#| label: fig-buying-reasons-category
#| fig-cap: "Reasons for buying or intending to buy fast tech, by item category"
#| fig-height: 8
item_reason_summary |>
mutate(
Reason_plot = str_wrap(Reason, width = 42)
) |>
ggplot(
aes(
x = pct,
y = fct_reorder(Reason_plot, pct)
)
) +
geom_col(
width = 0.52,
fill = bg_accent
) +
geom_text(
aes(label = percent(pct, accuracy = 0.1)),
hjust = -0.15,
size = bg_size_label / .pt
) +
scale_x_continuous(
labels = percent_format(),
expand = expansion(mult = c(0, 0.16))
) +
scale_y_discrete(
expand = expansion(add = 0.35)
) +
facet_wrap(
~Category,
ncol = 1,
scales = "free_y"
) +
labs(
x = "% selecting the reason",
y = NULL
) +
theme(
axis.text.y = element_text(
lineheight = 0.9
),
panel.spacing.y = grid::unit(32, "pt")
)
```
### Combined buying reasons across item categories
When the three fast tech categories are combined, **having a temporary replacement is the most widely reported buying reason (`r format_percent(item_reason_combined_pct[["As a temporary replacement"]])`)**. This is followed by buying an item as a spare device (`r format_percent(item_reason_combined_pct[["As a spare device"]])`), for work, study or everyday use (`r format_percent(item_reason_combined_pct[["For work, study or everyday use"]])`), and wanting a newer version (`r format_percent(item_reason_combined_pct[["I wanted a newer version"]])`).
Nearly a quarter of recent buyers selected buying an item despite not really needing it (`r format_percent(item_reason_combined_pct[["I bought it even though I didn't really need it"]])`), for at least one category.
> **Note:** Each reason is counted no more than once per respondent, even when it was selected for several categories. Respondents could select multiple reasons, so the percentages do not sum to 100%.
```{r}
#| label: fig-buying-reasons-combined
#| fig-cap: "Buying reasons across all non-vape fast tech categories"
item_reason_combined_summary |>
ggplot(aes(
x = pct,
y = fct_reorder(Reason_plot, pct)
)) +
geom_col(
width = bg_bar_width,
fill = bg_accent
) +
geom_text(
aes(label = percent(pct, accuracy = 0.1)),
hjust = -0.15,
size = bg_size_label / .pt
) +
scale_x_continuous(
labels = percent_format(),
expand = expansion(mult = c(0, 0.16))
) +
labs(
x = "% of eligible recent buyers",
y = NULL
)
```
## General reasons for buying fast tech
```{r}
#| label: general-buying-reasons-data
general_reason_cols <- c(
"They are more affordable",
"They are the only available option",
"They are easily available or showcased",
"I read positive reviews about them",
"Promotions or special deals",
"People I trust recommend them",
"I see them in ads or on social media",
"Curiosity, for fun, or trying something new",
"Other...88",
"I don’t know...89"
)
general_reason_summary <- df |>
select(analysis_weight, all_of(general_reason_cols)) |>
pivot_longer(
cols = all_of(general_reason_cols),
names_to = "Reason",
values_to = "Value"
) |>
filter(!is.na(Value)) |>
mutate(
Reason = recode(
Reason,
"Other...88" = "Other",
"I don’t know...89" = "I don’t know"
),
selected = is_selected(Value)
) |>
group_by(Reason) |>
summarise(
n = sum(selected),
denominator = n(),
pct = weighted_mean_safe(selected, analysis_weight),
.groups = "drop"
) |>
arrange(desc(pct)) |>
mutate(
Reason_plot = str_wrap(Reason, width = 38)
)
general_reason_percent <- setNames(
general_reason_summary$pct,
general_reason_summary$Reason
)
```
::: question
**Q10.** Generally speaking, what makes you buy small and inexpensive electronic devices rather than more expensive alternatives?
:::
**Half of respondents designated price as a purchasing driver** (`r format_percent(general_reason_percent[["They are more affordable"]])`). Together with promotions (`r format_percent(general_reason_percent[["Promotions or special deals"]])`), this makes **affordability the leading reported reason** Availability or product visibility is the second reason (`r format_percent(general_reason_percent[["They are easily available or showcased"]])`).
Social influences seem to have a smaller impact: positive reviews by `r format_percent(general_reason_percent[["I read positive reviews about them"]])`, recommendations from trusted people by `r format_percent(general_reason_percent[["People I trust recommend them"]])`, and advertising or social media by `r format_percent(general_reason_percent[["I see them in ads or on social media"]])`.
> **Note:** this was also a multiple-response question.
```{r}
#| label: fig-general-buying-reasons
#| fig-cap: "General reasons for buying fast tech"
general_reason_summary |>
ggplot(aes(
x = pct,
y = fct_reorder(Reason_plot, pct)
)) +
geom_col(width = bg_bar_width, fill = bg_accent) +
geom_text(
aes(label = percent(pct, accuracy = 0.1)),
hjust = -0.15,
size = bg_size_label / .pt
) +
scale_x_continuous(
labels = percent_format(),
expand = expansion(mult = c(0, 0.16))
) +
labs(
x = "% of respondents who have ever bought fast tech",
y = NULL
)
```
## Purchase channels
```{r}
#| label: purchase-channels-data
purchase_channel_cols <- c(
"On the brand’s website",
"Online stores, marketplaces, social media",
"Tobacconist, convenience store",
"Physical stores, outdoor stall, market store",
"At the airport or a train station",
"As gifts, professional giveaways or merch",
"Second hand platform",
"I don’t remember...99",
"Other...98"
)
purchase_channel_summary <- df |>
select(analysis_weight, all_of(purchase_channel_cols)) |>
pivot_longer(
cols = all_of(purchase_channel_cols),
names_to = "Channel",
values_to = "Value"
) |>
filter(!is.na(Value)) |>
mutate(
Channel = recode(
Channel,
"I don’t remember...99" = "I don’t remember",
"Other...98" = "Other"
),
selected = is_selected(Value)
) |>
group_by(Channel) |>
summarise(
n = sum(selected),
denominator = n(),
pct = weighted_mean_safe(selected, analysis_weight),
.groups = "drop"
) |>
arrange(desc(pct)) |>
mutate(
Channel_plot = str_wrap(Channel, width = 40)
)
purchase_channel_pct <- setNames(
purchase_channel_summary$pct,
purchase_channel_summary$Channel
)
```
::: question
**Q11.** Where do you usually get your small and inexpensive electronic devices (no matter the category)?
:::
Online stores, marketplaces and social media are the most frequently reported purchase channels, selected by **`r format_percent(purchase_channel_pct[["Online stores, marketplaces, social media"]])` of buyers**. Physical stores, outdoor stalls and market stores follow closely (`r format_percent(purchase_channel_pct[["Physical stores, outdoor stall, market store"]])`), while `r format_percent(purchase_channel_pct[["On the brand’s website"]])` buy directly from brand websites. All other channels were selected by fewer than one buyer in seven.
> **Note:** Respondents could select more than one purchase channel, so percentages do not sum to 100%.
```{r}
#| label: fig-purchase-channels
#| fig-cap: "Usual channels for obtaining fast tech devices"
purchase_channel_summary |>
mutate(
response_type = if_else(
Channel %in% c("I don’t remember", "Other"),
"Non-substantive response",
"Purchase channel"
)
) |>
ggplot(aes(
x = pct,
y = fct_reorder(Channel_plot, pct),
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(
"Purchase channel" = bg_accent,
"Non-substantive response" = bg_ink_32
),
guide = "none"
) +
scale_x_continuous(
labels = percent_format(),
expand = expansion(mult = c(0, 0.16))
) +
labs(
x = "% of buyers",
y = NULL
)
```
## Fast tech items still in use today
```{r}
#| label: still-use-data
still_use_summary <- df |>
filter(
Buy_12months == "Buyer",
!is.na(`12months_still use`)
) |>
mutate(
Band = factor(
as.character(`12months_still use`),
levels = buying_band_levels
)
) |>
group_by(Band, .drop = FALSE) |>
summarise(
n = n(),
weighted_n = sum(analysis_weight),
.groups = "drop"
) |>
mutate(pct = weighted_n / sum(weighted_n))
still_use_percent_by_band <- setNames(
still_use_summary$pct,
as.character(still_use_summary$Band)
)
```
::: question
**Q12.** Among all the small and inexpensive electronic devices you’ve bought during the last 12 months, how many do you still personally use today?
:::
Among respondents who purchased fast tech during the last 12 months, **`r format_percent(still_use_percent_by_band[["2 to 5"]])` report that two to five items are still in use**; `r format_percent(still_use_percent_by_band[["1"]])` report one item, while `r format_percent(still_use_percent_by_band[["0"]])` report that none of the items are still in use.
> **Note:** we've only asked about the items recently bought (less than a year).
```{r}
#| label: fig-fast-tech-still-use
#| fig-cap: "Number of fast tech items purchased during the last 12 months that are still in use"
still_use_summary |>
ggplot(aes(x = Band, 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.12))
) +
labs(
x = "Number of items still in use",
y = "% of respondents who purchased fast tech\nin the last 12 months"
)
```
## Shortest duration of use
```{r}
#| label: shortest-use-data
shortest_use_levels <- c(
"I got rid of it without ever using it",
"Single-use",
"Less than a week",
"Less than a month",
"1 to 6 months",
"6 to 12 months",
"12 months or more",
"I don’t know / don’t remember"
)
shortest_use_summary <- summarise_response_distribution(
df,
"Shortest_used",
shortest_use_levels
)
pct_shortest_under_month <- shortest_use_summary |>
filter(
Response %in% c(
"I got rid of it without ever using it",
"Single-use",
"Less than a week",
"Less than a month"
)
) |>
summarise(pct = sum(pct)) |>
pull(pct)
shortest_use_pct <- setNames(
shortest_use_summary$pct,
as.character(shortest_use_summary$Response)
)
pct_shortest_within_six_months <-
pct_shortest_under_month +
shortest_use_pct[["1 to 6 months"]]
```
::: question
**Q13.** Think about the small and inexpensive electronic devices you’ve ever had (excluding disposable e-cigarettes). What is the shortest period of time you have used one of them before discarding it?
:::
More than a third of previous buyers (`r format_percent(pct_shortest_under_month)`) recalled their shortest-lived fast tech device was discarded without being used, after a single use or within one month. Overall, **`r format_percent(pct_shortest_within_six_months)` declared that their *shortest-lived* fast tech device lasted no more than six months.**
```{r}
#| label: fig-shortest-use
#| fig-cap: "Shortest recalled period of use before discarding a fast tech device"
shortest_use_summary |>
mutate(
response_type = if_else(
Response == "I don’t know / don’t remember",
"Don’t know",
"Reported duration"
)
) |>
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(
"Reported duration" = bg_accent,
"Don’t know" = 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 = 38)
) +
labs(
x = "% of previous buyers",
y = NULL
)
```
------------------------------------------------------------------------
# End-of-Life Behaviour
```{r}
#| label: end-of-life-data
eol_band_levels <- c(
"0", "1", "2 to 5", "6 to 9", "10 to 19", "20+"
)
```
## Items disposed of during the last 12 months
```{r}
#| label: disposed-items-data
disposed_long <- df |>
select(analysis_weight, all_of(disposed_cols)) |>
pivot_longer(
all_of(disposed_cols),
names_to = "Category",
values_to = "Code"
) |>
filter(!is.na(Code)) |>
mutate(
Category = str_remove(
Category,
"^12months_disposed_"
),
Category = recode(
Category,
"Gadget and lifestyle items" =
"Gadgets & lifestyle items"
),
# The recoded file stores the six response categories
# as numeric codes from 1 to 6.
Band = recode(
as.character(Code),
"1" = "0",
"2" = "1",
"3" = "2 to 5",
"4" = "6 to 9",
"5" = "10 to 19",
"6" = "20+"
),
Band = factor(
Band,
levels = eol_band_levels
)
)
disposed_summary <- disposed_long |>
group_by(Category) |>
summarise(
n_eligible = n(),
n_disposed = sum(Band != "0"),
pct = weighted_mean_safe(Band != "0", analysis_weight),
.groups = "drop"
)
format_disposed_percent <- function(category) {
format_percent(
disposed_summary$pct[
disposed_summary$Category == category
]
)
}
disposed_code_min <- c(
"1" = 0,
"2" = 1,
"3" = 2,
"4" = 6,
"5" = 10,
"6" = 20
)
disposed_code_max <- c(
"1" = 0,
"2" = 1,
"3" = 5,
"4" = 9,
"5" = 19,
"6" = Inf
)
disposed_combined_levels <- c(
"No item disposed of",
"Exactly 1 item",
"Definitely 2 to 5 items",
"Could be 2 to 5 or 6+ items",
"Definitely 6 or more items"
)
disposed_combined <- df |>
transmute(
analysis_weight,
across(
all_of(disposed_non_vape_cols),
as.character
)
) |>
filter(
if_all(
all_of(disposed_non_vape_cols),
~ !is.na(.x)
)
) |>
mutate(
total_min = rowSums(
across(
all_of(disposed_non_vape_cols),
\(x) unname(disposed_code_min[x])
)
),
total_max = rowSums(
across(
all_of(disposed_non_vape_cols),
\(x) unname(disposed_code_max[x])
)
),
Combined_total = case_when(
total_max == 0 ~ "No item disposed of",
total_min == 1 & total_max == 1 ~ "Exactly 1 item",
total_min >= 2 & total_max <= 5 ~ "Definitely 2 to 5 items",
total_min > 5 ~ "Definitely 6 or more items",
TRUE ~ "Could be 2 to 5 or 6+ items"
),
Combined_total = factor(
Combined_total,
levels = disposed_combined_levels
)
)
disposed_combined_summary <- disposed_combined |>
group_by(Combined_total, .drop = FALSE) |>
summarise(
n = n(),
weighted_n = sum(analysis_weight),
.groups = "drop"
) |>
mutate(pct = weighted_n / sum(weighted_n)) |>
arrange(Combined_total)
disposed_combined_pct <- setNames(
disposed_combined_summary$pct,
as.character(disposed_combined_summary$Combined_total)
)
pct_any_disposed_non_vape <- 1 -
disposed_combined_pct[["No item disposed of"]]
pct_exactly_one_disposed_non_vape <- disposed_combined_pct[[
"Exactly 1 item"
]]
pct_definitely_six_plus_disposed_non_vape <- disposed_combined_pct[[
"Definitely 6 or more items"
]]
pct_definitely_two_five_disposed_non_vape <- disposed_combined_pct[[
"Definitely 2 to 5 items"
]]
pct_possible_two_five_disposed_non_vape <-
pct_definitely_two_five_disposed_non_vape +
disposed_combined_pct[["Could be 2 to 5 or 6+ items"]]
```
::: question
**Q14.** Over the last 12 months, how many of the following items have you personally disposed of?
:::
Among respondents who have ever bought fast tech, **`r format_disposed_percent("Charging & lighting devices")` disposed of at least one charging or lighting device** during the past year, making this category the most widely disposed of, which is coherent with the quantity owned, purchased, and buying intentions.
Half respondents disposed of at least one high-tech item (`r format_disposed_percent("High-tech")`) or gadget and lifestyle item (`r format_disposed_percent("Gadgets & lifestyle items")`). The proportion was lower for e-vapes, at `r format_disposed_percent("E-vapes")`.
```{r}
#| label: fig-eol-disposed-share
#| fig-cap: "Share of previous buyers who disposed of at least one item during the last 12 months, by category"
disposed_summary |>
mutate(
category_type = if_else(
Category == "E-vapes",
"E-vapes",
"Other categories"
)
) |>
ggplot(aes(
x = reorder(Category, pct),
y = pct,
fill = category_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(
"Other categories" = bg_accent,
"E-vapes" = bg_ink_32
),
guide = "none"
) +
scale_y_continuous(
labels = percent_format(),
limits = c(0, NA),
expand = expansion(mult = c(0, 0.12))
) +
coord_flip() +
labs(
x = NULL,
y = "% disposing of at least one item"
)
```
### Distribution of the number of items disposed of
Charging and lighting devices are disposed of more frequently and in larger numbers than the other categories, which, again, is consistent with previous results on buying behaviour, ownership and purchase intentions. For high-tech products and gadgets and lifestyle items, reporting no disposal remains the most frequent individual response.
```{r}
#| label: fig-eol-disposed-quantity
#| fig-cap: "Number of fast tech items disposed of during the last 12 months, by category"
#| fig-height: 7
category_order <- c(
"Charging & lighting devices",
"Gadgets & lifestyle items",
"High-tech",
"E-vapes"
)
disposed_long |>
group_by(Category, Band, .drop = FALSE) |>
summarise(n = n(), weighted_n = sum(analysis_weight), .groups = "drop_last") |>
group_by(Category) |>
mutate(pct = weighted_n / sum(weighted_n)) |>
ungroup() |>
mutate(
Category = factor(
Category,
levels = category_order
),
band_type = if_else(
as.character(Band) == "0",
"No item disposed of",
"At least one item disposed of"
)
) |>
ggplot(aes(
x = Band,
y = pct,
fill = band_type
)) +
geom_col(width = bg_bar_width) +
geom_text(
aes(
label = if_else(
pct >= 0.02,
percent(pct, accuracy = 0.1),
""
)
),
vjust = -0.4,
size = bg_size_label / .pt
) +
scale_fill_manual(
values = c(
"No item disposed of" = bg_ink_32,
"At least one item disposed of" = bg_accent
),
guide = "none"
) +
scale_y_continuous(
labels = percent_format(),
expand = expansion(mult = c(0, 0.14))
) +
facet_wrap(
~Category,
ncol = 2
) +
labs(
x = "Number of items disposed of",
y = "% of previous buyers"
) +
theme(
axis.text.x = element_text(
angle = 30,
hjust = 1
),
panel.spacing.y = grid::unit(32, "pt")
)
```
### Combined quantity across categories (excluding e-vapes)
Across the three non-vape categories, **`r format_percent(pct_any_disposed_non_vape)` of previous buyers disposed of at least one fast tech item during the last 12 months**. `r format_percent(pct_exactly_one_disposed_non_vape)` disposed of exactly one item, while at least `r format_percent(pct_definitely_six_plus_disposed_non_vape)` disposed of six or more.
The exact share disposing of two to five items in total lies between **`r format_percent(pct_definitely_two_five_disposed_non_vape)`** and **`r format_percent(pct_possible_two_five_disposed_non_vape)`**, depending on the exact counts within each category range.
> **Note:** Combined quantities exclude e-vapes and use previous buyers with valid answers for all three categories. Since Q14 records ranges, combined totals preserve uncertainty rather than imputing exact counts.
```{r}
#| label: fig-eol-disposed-quantity-combined
#| fig-cap: "Combined quantity of fast tech items disposed of during the last 12 months, excluding e-vapes"
disposed_combined_summary |>
mutate(
total_type = case_when(
Combined_total == "No item disposed of" ~ "None",
Combined_total == "Could be 2 to 5 or 6+ items" ~ "Range uncertainty",
TRUE ~ "Classified total"
)
) |>
ggplot(aes(
x = pct,
y = fct_rev(Combined_total),
fill = total_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(
"None" = bg_ink_32,
"Range uncertainty" = bg_blue_50,
"Classified total" = bg_accent
),
guide = "none"
) +
scale_x_continuous(
labels = percent_format(),
expand = expansion(mult = c(0, 0.16))
) +
labs(
x = "% of previous buyers",
y = NULL
)
```
## Reasons for stopping use
```{r}
#| label: stopped-use-reasons-data
stopped_reason_summary <- df |>
select(analysis_weight, all_of(stopping_reason_cols)) |>
pivot_longer(
all_of(stopping_reason_cols),
names_to = "Reason",
values_to = "Value"
) |>
filter(!is.na(Value)) |>
mutate(
Reason = recode(
Reason,
"Other...114" = "Other"
),
selected = is_selected(Value)
) |>
group_by(Reason) |>
summarise(
n = sum(selected),
denominator = n(),
pct = weighted_mean_safe(selected, analysis_weight),
.groups = "drop"
) |>
arrange(desc(pct))
format_stopping_reason_percent <- function(reason) {
format_percent(
stopped_reason_summary$pct[
stopped_reason_summary$Reason == reason
]
)
}
```
::: question
**Q15.** What are the main reasons why you stopped using your small and inexpensive electronic devices?
:::
**Product failure is the main reason** for stopping use. More than **half of respondents (`r format_stopping_reason_percent("They broke or became defective")`) reported that an item broke or became defective**, `r format_stopping_reason_percent("They stopped working, although physically okay")` said that an item stopped working despite appearing physically intact, and `r format_stopping_reason_percent("They became dangerous")` reported the item became dangerous, underlying some defect.
A smaller proportion no longer needed the item (`r format_stopping_reason_percent("I didn’t need them anymore")`) or considered it outdated or obsolete (`r format_stopping_reason_percent("They were outdated, out of fashion or obsolete")`).
> **Note:** Respondents could select up to two reasons.
```{r}
#| label: fig-eol-stopped-use-reasons
#| fig-cap: "Reasons for stopping use of fast tech items"
stopped_reason_summary |>
mutate(
Reason_plot = str_wrap(Reason, width = 42)
) |>
ggplot(aes(
x = pct,
y = fct_reorder(Reason_plot, pct)
)) +
geom_col(width = bg_bar_width, fill = bg_accent) +
geom_text(
aes(label = percent(pct, accuracy = 0.1)),
hjust = -0.15,
size = bg_size_label / .pt
) +
scale_x_continuous(
labels = percent_format(),
expand = expansion(mult = c(0, 0.15))
) +
labs(
x = "% of eligible respondents",
y = NULL
)
```
## Disposal habits
```{r}
#| label: disposal-methods-data
disposal_method_summary <- df |>
select(analysis_weight, all_of(disposal_method_cols)) |>
pivot_longer(
all_of(disposal_method_cols),
names_to = "Method",
values_to = "Value"
) |>
filter(!is.na(Value)) |>
mutate(
Method = recode(
Method,
"Other...124" = "Other",
"I don’t remember...125" =
"I don’t remember"
),
selected = is_selected(Value)
) |>
group_by(Method) |>
summarise(
n = sum(selected),
denominator = n(),
pct = weighted_mean_safe(selected, analysis_weight),
.groups = "drop"
) |>
arrange(desc(pct))
disposal_method_percent <- setNames(
disposal_method_summary$pct,
disposal_method_summary$Method
)
disposal_profile_summary <- disposal_response_data |>
group_by(Profile) |>
summarise(
n = n(),
weighted_n = sum(analysis_weight),
.groups = "drop"
) |>
mutate(
Profile = factor(
Profile,
levels = disposal_profile_levels
),
pct = weighted_n / sum(weighted_n)
) |>
arrange(Profile)
disposal_profile_pct <- setNames(
disposal_profile_summary$pct,
as.character(disposal_profile_summary$Profile)
)
n_disposal_respondents <- nrow(
disposal_response_data
)
n_single_disposal_method <- sum(
disposal_response_data$n_selected == 1
)
pct_single_disposal_method <-
weighted_mean_safe(
disposal_response_data$n_selected == 1,
disposal_response_data$analysis_weight
)
n_multiple_disposal_methods <- sum(
disposal_response_data$n_selected > 1
)
pct_multiple_disposal_methods <-
weighted_mean_safe(
disposal_response_data$n_selected > 1,
disposal_response_data$analysis_weight
)
disposal_unique_summary <- disposal_response_data |>
filter(n_selected == 1) |>
select(
analysis_weight,
all_of(c(
disposal_recycling_reuse_cols,
disposal_waste_cols,
disposal_kept_cols
))
) |>
pivot_longer(
-analysis_weight,
names_to = "Method",
values_to = "selected"
) |>
filter(selected) |>
mutate(
Method = recode(
Method,
"Other...124" = "Other",
"I don’t remember...125" =
"I don’t remember"
)
) |>
group_by(Method) |>
summarise(
n = n(),
weighted_n = sum(analysis_weight),
.groups = "drop"
) |>
mutate(pct = weighted_n / sum(weighted_n)) |>
arrange(desc(pct))
```
::: question
**Q16.** Thinking about all the devices you have stopped using, what have you done with them?
:::
Just like casual electronic devices, keeping unused items at home is the most common reported behaviour (`r format_percent(disposal_method_percent[["I kept them"]])` of buyers). **`r format_percent(disposal_method_percent[["I brought them to a recycling centre / municipal waste facility"]])` report bringing devices to a recycling centre or municipal waste facility**, and `r format_percent(disposal_method_percent[["I brought them to a recycling point in a store"]])` report using a store collection point. Reuse options were selected less often: `r format_percent(disposal_method_percent[["I gave them away or donated"]])` gave devices away or donated them and `r format_percent(disposal_method_percent[["I sold them"]])` sold them.
Inappropriate disposal seem to remain frequent: **`r format_percent(disposal_method_percent[["I threw them in general household waste"]])` reported throwing an item into general household waste**, `r format_percent(disposal_method_percent[["I threw them in the plastic waste bin"]])` into the plastic waste bin, and `r format_percent(disposal_method_percent[["I threw them in a street bin"]])` into a street bin.
> **Note:** the plastic-waste-bin option was not displayed in Switzerland.
```{r}
#| label: fig-eol-disposal-methods
#| fig-cap: "What respondents did with fast tech devices they stopped using"
disposal_method_summary |>
mutate(
method_type = case_when(
Method %in% c(
"I brought them to a recycling centre / municipal waste facility",
"I brought them to a recycling point in a store",
"I gave them away or donated",
"I sold them"
) ~ "Recycling or reuse",
Method %in% c(
"I kept them",
"I don’t remember",
"Other"
) ~ "Kept, other or unknown",
TRUE ~ "Waste disposal"
),
Method_plot = str_wrap(Method, width = 44)
) |>
ggplot(aes(
x = pct,
y = fct_reorder(Method_plot, pct),
fill = method_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(
name = NULL,
values = c(
"Recycling or reuse" = bg_accent,
"Kept, other or unknown" = bg_ink_32,
"Waste disposal" = bg_pink
),
guide="none"
) +
scale_x_continuous(
labels = percent_format(),
expand = expansion(mult = c(0, 0.16))
) +
labs(
x = "% of buyers",
y = NULL
)
```
### Mutually exclusive disposal profiles
If we group the disposal methods, we see that **`r format_percent(disposal_profile_pct[["Recycling or reuse only"]])` reported recycling or reuse methods only**, whereas `r format_percent(disposal_profile_pct[["Waste disposal only"]])` reported waste-disposal methods only. A further `r format_percent(disposal_profile_pct[["Kept only"]])` reported only keeping devices, and **`r format_percent(disposal_profile_pct[["Mixed methods"]])` combined methods belonging to more than one group.**
> **Note:** “Other” and “I don’t remember” are excluded.
```{r}
#| label: fig-eol-disposal-profiles
#| fig-cap: "Mutually exclusive disposal profiles among previous buyers"
disposal_profile_summary |>
ggplot(aes(
x = pct,
y = fct_rev(Profile),
fill = Profile
)) +
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(
"Recycling or reuse only" = bg_accent,
"Waste disposal only" = bg_pink,
"Kept only" = bg_ink_32,
"Mixed methods" = bg_blue
),
guide = "none"
) +
scale_x_continuous(
labels = percent_format(),
expand = expansion(mult = c(0, 0.16))
) +
labs(
x = "% of previous buyers",
y = NULL
)
```
### Disposal profiles by country
```{r}
#| label: disposal-profiles-country-data
disposal_profile_country_summary <- disposal_response_data |>
left_join(
df |>
transmute(
respondent_id = row_number(),
Country
),
by = "respondent_id"
) |>
mutate(
Profile = factor(
Profile,
levels = disposal_profile_levels
)
) |>
group_by(
Country,
Profile,
.drop = FALSE
) |>
summarise(
n = n(),
weighted_n = sum(country_weight),
.groups = "drop_last"
) |>
mutate(pct = weighted_n / sum(weighted_n)) |>
ungroup()
disposal_profile_country_order <-
disposal_profile_country_summary |>
filter(Profile == "Recycling or reuse only") |>
arrange(pct) |>
pull(Country)
disposal_profile_country_extremes <-
disposal_profile_country_summary |>
filter(
Profile %in% c(
"Recycling or reuse only",
"Waste disposal only"
)
) |>
group_by(Profile) |>
summarise(
highest_country = Country[which.max(pct)],
highest_pct = max(pct),
lowest_country = Country[which.min(pct)],
lowest_pct = min(pct),
.groups = "drop"
)
country_recycling_profile_extremes <-
disposal_profile_country_extremes |>
filter(Profile == "Recycling or reuse only")
country_bin_profile_high <-
disposal_profile_country_extremes |>
filter(Profile == "Waste disposal only")
```
The distribution between disposal habits differs across countries. Reporting **recycling or reuse only** ranges from `r format_percent(country_recycling_profile_extremes$lowest_pct)` in `r country_recycling_profile_extremes$lowest_country` to `r format_percent(country_recycling_profile_extremes$highest_pct)` in `r country_recycling_profile_extremes$highest_country`.
> **Note:** Percentages are calculated within each country. “Other” and “I don’t remember” answers are excluded. Respondents selecting identifiable methods from more than one route are classified as using mixed methods.
```{r}
#| label: fig-eol-disposal-profiles-country
#| fig-cap: "Mutually exclusive disposal profiles among previous buyers, by country"
#| fig-height: 7
disposal_profile_country_summary |>
mutate(
Country = factor(
Country,
levels = disposal_profile_country_order
),
Profile_plot = recode(
as.character(Profile),
"Waste disposal only" = "Bin disposal only"
),
Profile_plot = factor(
Profile_plot,
levels = c(
"Recycling or reuse only",
"Mixed methods",
"Kept only",
"Bin disposal only"
)
)
) |>
ggplot(aes(
x = pct,
y = Country,
fill = Profile_plot
)) +
geom_col(
width = bg_bar_width,
position = position_stack(reverse = TRUE)
) +
geom_text(
aes(
label = if_else(
pct >= 0.05,
percent(pct, accuracy = 0.1),
""
)
),
position = position_stack(
vjust = 0.5,
reverse = TRUE
),
colour = bg_ink,
size = bg_size_label / .pt
) +
scale_fill_manual(
name = NULL,
values = c(
"Recycling or reuse only" = bg_accent,
"Mixed methods" = bg_blue,
"Kept only" = bg_ink_32,
"Bin disposal only" = bg_pink
),
drop = FALSE
) +
scale_x_continuous(
labels = percent_format(),
breaks = seq(0, 1, by = 0.25),
expand = expansion(mult = c(0, 0.02))
) +
labs(
x = "% within each country",
y = NULL
) +
theme(
legend.position = "top",
panel.grid.major.y = element_blank()
)
```
### Disposal method among single-option respondents
**`r format_count(n_single_disposal_method)` respondents (`r format_percent(pct_single_disposal_method)`) selected only one disposal option.** Within this group, keeping the devices and taking them to a recycling centre or municipal waste facility were the two most frequently reported outcomes.
> **Note:** The percentages below sum to 100%, but apply only to respondents who selected exactly one identifiable option. “Other” and “I don’t remember” are excluded. The analysis excludes `r format_count(n_multiple_disposal_methods)` respondents (`r format_percent(pct_multiple_disposal_methods)`) who reported more than one identifiable disposal method. This share is larger than the “Mixed methods” profile because respondents can select several methods belonging to the same profile, such as two recycling routes.
```{r}
#| label: fig-eol-disposal-single-option
#| fig-cap: "Disposal method among respondents selecting exactly one option"
#| fig-height: 6
disposal_unique_summary |>
mutate(
method_type = case_when(
Method %in% c(
"I brought them to a recycling centre / municipal waste facility",
"I brought them to a recycling point in a store",
"I gave them away or donated",
"I sold them"
) ~ "Recycling or reuse",
Method == "I kept them" ~ "Kept",
TRUE ~ "Waste disposal"
),
Method_plot = str_wrap(Method, width = 44)
) |>
ggplot(aes(
x = pct,
y = fct_reorder(Method_plot, pct),
fill = method_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(
"Recycling or reuse" = bg_accent,
"Kept" = bg_ink_32,
"Waste disposal" = bg_pink
),
guide = "none"
) +
scale_x_continuous(
labels = percent_format(),
expand = expansion(mult = c(0, 0.16))
) +
labs(
x = "% of single-option respondents",
y = NULL
)
```
## Reasons for choosing disposal solutions
```{r}
#| label: disposal-motivations-data
disposal_motivation_summary <- df |>
select(analysis_weight, all_of(disposal_motivation_cols)) |>
pivot_longer(
all_of(disposal_motivation_cols),
names_to = "Motivation",
values_to = "Value"
) |>
filter(!is.na(Value)) |>
mutate(
Motivation = recode(
Motivation,
"didn’t know where else to put it" =
"I didn’t know where else to put it",
"Other...132" = "Other"
),
selected = is_selected(Value)
) |>
group_by(Motivation) |>
summarise(
n = sum(selected),
denominator = n(),
pct = weighted_mean_safe(selected, analysis_weight),
.groups = "drop"
) |>
arrange(desc(pct))
disposal_motivation_percent <- setNames(
disposal_motivation_summary$pct,
disposal_motivation_summary$Motivation
)
disposal_profile_motivation_summary <- df |>
mutate(
respondent_id = row_number()
) |>
select(
respondent_id,
analysis_weight,
all_of(disposal_motivation_cols)
) |>
pivot_longer(
all_of(disposal_motivation_cols),
names_to = "Motivation",
values_to = "Value"
) |>
filter(!is.na(Value)) |>
mutate(
Motivation = recode(
Motivation,
"didn’t know where else to put it" =
"I didn’t know where else to put it",
"Other...132" = "Other"
),
selected = is_selected(Value)
) |>
inner_join(
disposal_response_data |>
select(
respondent_id,
Profile
),
by = "respondent_id"
) |>
group_by(
Profile,
Motivation
) |>
summarise(
n = sum(selected),
denominator = n(),
pct = weighted_mean_safe(selected, analysis_weight),
.groups = "drop"
) |>
mutate(
Profile = factor(
Profile,
levels = disposal_profile_levels
),
Motivation = factor(
Motivation,
levels = rev(
disposal_motivation_summary$Motivation
)
),
label_colour = if_else(
pct >= 0.38,
bg_white,
bg_ink
)
)
format_profile_motivation_percent <- function(
profile,
motivation
) {
format_percent(
disposal_profile_motivation_summary$pct[
disposal_profile_motivation_summary$Profile ==
profile &
disposal_profile_motivation_summary$Motivation ==
motivation
]
)
}
```
::: question
**Q17.** Why did you choose this or these solutions?
:::
**Habit is the leading reported explanation for respondents’ end-of-life choices:** `r format_percent(disposal_motivation_percent[["It’s what I usually do with this kind of waste"]])` selected what they usually do with that kind of waste. Environmental protection is the second reason (`r format_percent(disposal_motivation_percent[["I did it to protect the environment"]])`), while convenience (`r format_percent(disposal_motivation_percent[["It’s the easiest solution"]])`) and proximity (`r format_percent(disposal_motivation_percent[["It’s closest to home"]])`) are also quite commonly selected.
```{r}
#| label: fig-eol-disposal-motivations
#| fig-cap: "Reasons for choosing end-of-life solutions"
disposal_motivation_summary |>
mutate(
Motivation_plot = str_wrap(
Motivation,
width = 44
)
) |>
ggplot(aes(
x = pct,
y = fct_reorder(Motivation_plot, pct)
)) +
geom_col(width = bg_bar_width, fill = bg_accent) +
geom_text(
aes(label = percent(pct, accuracy = 0.1)),
hjust = -0.15,
size = bg_size_label / .pt
) +
scale_x_continuous(
labels = percent_format(),
expand = expansion(mult = c(0, 0.16))
) +
labs(
x = "% of previous buyers",
y = NULL
)
```
### Disposal motivations by disposal profile
The motivations reported for end-of-life choices vary with the disposal profile. Among respondents reporting **recycling or reuse only**, **environmental protection (`r format_profile_motivation_percent("Recycling or reuse only", "I did it to protect the environment")`)** and **habit (`r format_profile_motivation_percent("Recycling or reuse only", "It’s what I usually do with this kind of waste")`)** are the two leading motivations.
For respondents reporting **waste disposal only**, **ease is the leading motivation (`r format_profile_motivation_percent("Waste disposal only", "It’s the easiest solution")`), **followed by **habit (`r format_profile_motivation_percent("Waste disposal only", "It’s what I usually do with this kind of waste")`)**.
Interestingly, **`r format_profile_motivation_percent("Waste disposal only", "I did it to protect the environment")`** selected **environmental protection** despite reporting only waste-disposal routes, which may indicate uncertainty or lack of knowledge about appropriate e-waste disposal.
Keeping devices without reporting another identifiable outcome is primarily associated with ease (`r format_profile_motivation_percent("Kept only", "It’s the easiest solution")`), while `r format_profile_motivation_percent("Kept only", "I didn’t really think about it")` reported not really thinking about their choice.
> **Note:** Percentages are calculated within each mutually exclusive profile based on identifiable outcomes; “Other” and “I don’t remember” do not define a profile. Respondents could select several motivations, so percentages within a profile do not sum to 100%. The associations are descriptive and don't establish causation.
```{r}
#| label: fig-eol-profile-motivation-heatmap
#| fig-cap: "Reasons for choosing end-of-life solutions, by disposal profile"
#| fig-height: 6
disposal_profile_motivation_summary |>
ggplot(aes(
x = Profile,
y = Motivation,
fill = pct
)) +
geom_tile(
colour = bg_surface,
linewidth = 1
) +
geom_text(
aes(
label = percent(
pct,
accuracy = 0.1
),
colour = label_colour
),
size = bg_size_label / .pt
) +
scale_fill_bg_c(
palette = "seq",
name = "% within profile",
breaks = c(0, 0.25, 0.5),
limits = c(0, 0.55),
labels = percent_format()
) +
scale_colour_identity() +
scale_x_discrete(
labels = \(x) str_wrap(
x,
width = 12
)
) +
scale_y_discrete(
labels = \(x) str_wrap(
x,
width = 40
)
) +
labs(
x = NULL,
y = NULL
) +
theme(
axis.text.x = element_text(
lineheight = 0.9
),
panel.grid = element_blank(),
legend.position = "top"
)
```
------------------------------------------------------------------------
# Non-buyers
```{r}
#| label: non-buyers-data
nonbuyers <- df |>
filter(Buyer == "Non buyer")
n_nonbuyers <- nrow(nonbuyers)
pct_nonbuyers_unweighted <- n_nonbuyers / nrow(df)
pct_nonbuyers <- weighted_mean_safe(
df$Buyer == "Non buyer",
df$analysis_weight
)
```
Respondents were classified as non-buyers when they answered *No, never* to Q5 on ever having bought a small and inexpensive electronic device. The achieved sample contains **`r scales::comma(n_nonbuyers)` non-buyers** (`r format_percent(pct_nonbuyers_unweighted)` of respondents). After population weighting, they represent **`r format_percent(pct_nonbuyers)`** of the population covered by the study.
## Reasons for never having bought fast tech
```{r}
#| label: non-buyer-reasons-data
nonbuyer_reason_cols <- c(
"I don’t know where to buy them",
"I don’t need them or I already own similar items",
"prefer higher-quality, longer-lasting alternatives",
"Because of their impact on the environment",
"Because of their social impact",
"Someone else buys electronic devices at home",
"Other...36",
"I don’t know...37"
)
nonbuyer_reason_summary <- nonbuyers |>
select(analysis_weight, all_of(nonbuyer_reason_cols)) |>
pivot_longer(
all_of(nonbuyer_reason_cols),
names_to = "Reason",
values_to = "Value"
) |>
filter(!is.na(Value)) |>
mutate(
Reason = recode(
Reason,
"prefer higher-quality, longer-lasting alternatives" =
"I prefer higher-quality, longer-lasting alternatives",
"Other...36" = "Other",
"I don’t know...37" = "I don’t know"
),
selected = is_selected(Value)
) |>
group_by(Reason) |>
summarise(
n = sum(selected),
denominator = n(),
pct = weighted_mean_safe(selected, analysis_weight),
.groups = "drop"
) |>
arrange(desc(pct))
format_nonbuyer_reason_percent <- function(reason) {
format_percent(
nonbuyer_reason_summary$pct[
nonbuyer_reason_summary$Reason == reason
]
)
}
```
::: question
**Q6.** Which of these describe why you have never bought any small and inexpensive electronic device?
:::
**Perceived lack of need or already owning similar products** are the main reasons for never purchasing fast tech, selected by almost **half of non-buyers**.
Preference for higher-quality and longer-lasting alternatives ranks second (`r format_nonbuyer_reason_percent("I prefer higher-quality, longer-lasting alternatives")`). A further `r format_nonbuyer_reason_percent("I don’t know")` were unable to identify a specific reason.
Environmental concerns were selected by `r format_nonbuyer_reason_percent("Because of their impact on the environment")`, whereas social impact concerns were mentioned less frequently (`r format_nonbuyer_reason_percent("Because of their social impact")`).
> **Note:** Because respondents could select more than one answer, the percentages do not sum to 100%.
```{r}
#| label: fig-non-buyer-reasons
#| fig-cap: "Reasons for never having bought fast tech"
nonbuyer_reason_summary |>
mutate(
Reason_plot = str_wrap(Reason, width = 44)
) |>
ggplot(aes(
x = pct,
y = fct_reorder(Reason_plot, pct)
)) +
geom_col(width = bg_bar_width, fill = bg_accent) +
geom_text(
aes(label = percent(pct, accuracy = 0.1)),
hjust = -0.15,
size = bg_size_label / .pt
) +
scale_x_continuous(
labels = percent_format(),
expand = expansion(mult = c(0, 0.16))
) +
labs(
x = "% of non-buyers",
y = NULL
)
```
## Exposure to fast tech among non-buyers
```{r}
#| label: exposure-data
exposure_levels <- c(
"Everyday",
"At least once a week",
"At least once a month",
"Few times a year",
"Less or never"
)
exposure_comparison_summary <- df |>
filter(
!is.na(`SeeFast-tech`),
Buyer %in% c("Buyer", "Non buyer")
) |>
mutate(
Buyer_group = recode(
Buyer,
"Buyer" = "Buyers",
"Non buyer" = "Non-buyers"
),
Buyer_group = factor(
Buyer_group,
levels = c("Non-buyers", "Buyers")
),
Frequency = factor(
`SeeFast-tech`,
levels = exposure_levels
)
) |>
group_by(Buyer_group, Frequency, .drop = FALSE) |>
summarise(
n = n(),
weighted_n = sum(analysis_weight),
.groups = "drop_last"
) |>
group_by(Buyer_group) |>
mutate(pct = weighted_n / sum(weighted_n)) |>
ungroup()
# Retains the non-buyer subset used in the accompanying text.
nonbuyer_exposure_summary <- exposure_comparison_summary |>
filter(Buyer_group == "Non-buyers") |>
arrange(Frequency)
format_nonbuyer_exposure_percent <- function(frequency) {
format_percent(
nonbuyer_exposure_summary$pct[
nonbuyer_exposure_summary$Frequency == frequency
]
)
}
pct_exposed_weekly_by_group <- exposure_comparison_summary |>
filter(
Frequency %in% c(
"Everyday",
"At least once a week"
)
) |>
group_by(Buyer_group) |>
summarise(
pct = sum(pct),
.groups = "drop"
) |>
deframe()
```
::: question
**Q7.** How often do you come across small and inexpensive electronic devices? *(At work, at friends’, in shops, on the web or social media…)*
:::
**More than half of non-buyers report being very rarely or never exposed to fast tech items** (`r format_nonbuyer_exposure_percent("Less or never")`), which contrasts with **`r format_percent(pct_exposed_weekly_by_group[["Buyers"]])` of buyers** reporting being exposed daily or at least once a week.
> **Note:** These measures report buyers and non-buyers perceptions. They can be exposed without noticing or remembering.
```{r}
#| label: fig-exposure-comparison
#| fig-cap: "Frequency of exposure to fast tech, by purchasing status"
exposure_comparison_summary |>
mutate(
Frequency_plot = factor(
Frequency,
levels = rev(exposure_levels)
)
) |>
ggplot(aes(
x = Frequency_plot,
y = pct,
fill = Buyer_group
)) +
geom_col(
position = position_dodge(width = 0.74),
width = 0.64
) +
geom_text(
aes(label = percent(pct, accuracy = 0.1)),
position = position_dodge(width = 0.74),
hjust = -0.15,
size = bg_size_label / .pt
) +
scale_fill_manual(
name = NULL,
values = c(
"Buyers" = bg_accent,
"Non-buyers" = bg_accent_50
),
breaks = c(
"Buyers",
"Non-buyers"
)
) +
scale_y_continuous(
labels = percent_format(),
expand = expansion(mult = c(0, 0.16))
) +
coord_flip() +
labs(
x = NULL,
y = "% within each group"
)
```
------------------------------------------------------------------------
# Perception and Willingness
The forthcoming results describe a certain degree of indifference among an important proportion of the respondents regarding fast tech and its environmental impact, which does not seem to be perceived as a problem.
## Device satisfaction {#device-satisfaction}
```{r}
#| label: satisfaction-data
satisfaction_levels <- c(
"Very dissatisfied",
"Dissatisfied",
"Neither satisfied nor dissatisfied",
"Satisfied",
"Very satisfied"
)
satisfaction_summary <- summarise_response_distribution(
df,
"Satisfaction",
satisfaction_levels
)
pct_satisfied <- satisfaction_summary |>
filter(Response %in% c("Satisfied", "Very satisfied")) |>
summarise(pct = sum(pct)) |>
pull(pct)
pct_dissatisfied <- satisfaction_summary |>
filter(Response %in% c("Dissatisfied", "Very dissatisfied")) |>
summarise(pct = sum(pct)) |>
pull(pct)
```
::: question
**Q18.** Overall, thinking back on the small and inexpensive devices you used, you would say you are…
:::
Only **`r format_percent(pct_dissatisfied)`** declared to be unsatisfied of their fast tech devices. There's actually a strong majority being satisfied (**`r format_percent(pct_satisfied)`**), while the rest (`r format_percent(satisfaction_summary$pct[satisfaction_summary$Response == "Neither satisfied nor dissatisfied"])`) express a neutral opinion.
> **Note:** Question 18 was shown only to respondents who had previously bought fast tech.
```{r}
#| label: fig-device-satisfaction
#| fig-cap: "Overall satisfaction with fast tech devices"
satisfaction_summary |>
ggplot(aes(x = Response, 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.12))
) +
labs(x = NULL, y = "% of previous buyers") +
theme(
axis.text.x = element_text(angle = 25, hjust = 1)
)
```
## Willingness to pay more
```{r}
#| label: willingness-pay-data
pay_more_summary <- summarise_response_distribution(
df,
"Pay more",
willingness_to_pay_levels
)
pct_willing_pay_more <- pay_more_summary |>
filter(Response != "No") |>
summarise(pct = sum(pct)) |>
pull(pct)
```
::: question
**Q19.** When you bought those small and inexpensive devices, would you have been willing to pay more for similar items that you could use over a longer time period?
:::
Even though most of them report to be satisfied with they fast tech items, a majority of buyers (**`r format_percent(pct_willing_pay_more)`) would have been willing to pay more for longer-lasting alternatives**. More than half of the buyers are willing to pay more for *some* items, rather than for *most* or *all* purchases.
```{r}
#| label: fig-willingness-pay-more
#| fig-cap: "Willingness to pay more for longer-lasting alternatives"
pay_more_summary |>
mutate(
response_type = if_else(
as.character(Response) == "No",
"No",
"Other responses"
)
) |>
ggplot(aes(
x = Response,
y = pct,
fill = response_type
)) +
geom_col(width = bg_bar_width) +
geom_text(
aes(label = percent(pct, accuracy = 0.1)),
vjust = -0.4,
size = bg_size_label / .pt
) +
scale_fill_manual(
values = c(
"Other responses" = bg_accent,
"No" = bg_ink_32
),
guide = "none"
) +
scale_y_continuous(
labels = percent_format(),
expand = expansion(mult = c(0, 0.12))
) +
labs(
x = NULL,
y = "% of previous buyers"
) +
theme(
axis.text.x = element_text(
angle = 25,
hjust = 1
)
)
```
## Willingness to replace
```{r}
#| label: replacement-data
replacement_summary <- summarise_response_distribution(
df,
"Replace",
replacement_choice_levels
)
pct_replace_inexpensive <- replacement_summary |>
filter(Response %in% c(
"Buy the exact same small and inexpensive model",
"Buy another small and inexpensive device"
)) |>
summarise(pct = sum(pct)) |>
pull(pct)
```
::: question
**Q20.** If you had to replace a small and inexpensive electronic device that broke, you would…
:::
If a fast tech device broke, **`r format_percent(pct_replace_inexpensive)` of previous buyers would replace it with the same model or another small and inexpensive device**. By contrast, `r format_percent(replacement_summary$pct[replacement_summary$Response == "Buy a more expensive one"])` would move to a more expensive alternative, while `r format_percent(replacement_summary$pct[replacement_summary$Response == "Choose not to replace it"])` would not replace the device.
That results echoes with the result on [device satisfaction](#device-satisfaction), showing that more than half of the buyers are satisfied with their fast tech devices. Since it brings overall satisfaction, it is logical to be willing to replace one's fast tech device by another one, if not the same. There are still interrogation as to why most of the respondents would have been willing to pay more to replace some by a more durable device.
```{r}
#| label: fig-replacement-intention
#| fig-cap: "Intended response if a fast tech device broke"
replacement_summary |>
mutate(Response_plot = str_wrap(Response, width = 38)) |>
ggplot(aes(
x = pct,
y = fct_reorder(Response_plot, pct)
)) +
geom_col(width = bg_bar_width, fill = bg_accent) +
geom_text(
aes(label = percent(pct, accuracy = 0.1)),
hjust = -0.15,
size = bg_size_label / .pt
) +
scale_x_continuous(
labels = percent_format(),
expand = expansion(mult = c(0, 0.16))
) +
labs(x = "% of previous buyers", y = NULL)
```
## Lifespan and quality compared to expectations
```{r}
#| label: product-expectations-data
lifespan_expectation_levels <- c(
"Shorter lifespan",
"Expected lifespan",
"Longer lifespan"
)
quality_expectation_levels <- c(
"Lower quality",
"Expected quality",
"Higher quality"
)
lifespan_expectation_summary <- summarise_response_distribution(
df,
"Global_Lifespan",
lifespan_expectation_levels
) |>
mutate(Measure = "Lifespan")
quality_expectation_data <- df |>
mutate(
Global_Quality = recode(
Global_Quality,
"Hgher quality" = "Higher quality"
)
)
quality_expectation_summary <- summarise_response_distribution(
quality_expectation_data,
"Global_Quality",
quality_expectation_levels
) |>
mutate(Measure = "Quality")
product_expectation_summary <- bind_rows(
lifespan_expectation_summary,
quality_expectation_summary
)
extract_product_expectation_proportion <- function(
measure,
response
) {
product_expectation_summary |>
filter(
Measure == measure,
Response == response
) |>
pull(pct)
}
pct_lifespan_met_or_exceeded <-
product_expectation_summary |>
filter(
Measure == "Lifespan",
Response %in% c(
"Expected lifespan",
"Longer lifespan"
)
) |>
summarise(pct = sum(pct)) |>
pull(pct)
pct_quality_met_or_exceeded <-
product_expectation_summary |>
filter(
Measure == "Quality",
Response %in% c(
"Expected quality",
"Higher quality"
)
) |>
summarise(pct = sum(pct)) |>
pull(pct)
```
::: question
**Q21.** Globally, would you say that your small and inexpensive electronic devices…
**Q21a.** …have a shorter lifespan than you expected, the lifespan you expected, or a longer lifespan than you expected?
**Q21b.** …are of lower quality than you expected, the quality you expected, or higher quality than you expected?
:::
The results are similar across the two dimensions. Around one quarter report outcomes **below their expectations** (`r format_percent(extract_product_expectation_proportion("Lifespan", "Shorter lifespan"))` for lifespan and `r format_percent(extract_product_expectation_proportion("Quality", "Lower quality"))` for quality), whereas around one in ten report outcomes **above their expectations** (`r format_percent(extract_product_expectation_proportion("Lifespan", "Longer lifespan"))` and `r format_percent(extract_product_expectation_proportion("Quality", "Higher quality"))`, respectively).
The interesting result is that a majority of previous buyers consider that fast tech devices **meet or exceed their expectations**: `r format_percent(pct_lifespan_met_or_exceeded)` for lifespan and `r format_percent(pct_quality_met_or_exceeded)` for quality.
```{r}
#| label: fig-product-expectations
#| fig-cap: "Perceived lifespan and quality of fast tech relative to expectations"
product_expectation_summary |>
mutate(
assessment = case_when(
Response %in% c(
"Shorter lifespan",
"Lower quality"
) ~ "Below expectations",
Response %in% c(
"Expected lifespan",
"Expected quality"
) ~ "As expected",
TRUE ~ "Above expectations"
)
) |>
ggplot(aes(
x = pct,
y = fct_rev(Response),
fill = assessment
)) +
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(
"Below expectations" = bg_pink,
"As expected" = bg_ink_32,
"Above expectations" = bg_accent
),
guide = "none"
) +
scale_x_continuous(
labels = percent_format(),
expand = expansion(mult = c(0, 0.16))
) +
facet_wrap(
~Measure,
ncol = 1,
scales = "free_y"
) +
labs(
x = "% of previous buyers",
y = NULL
) +
theme(
panel.spacing.y = grid::unit(26, "pt")
)
```
## Lifespan and environmental impact relative to more expensive alternatives
```{r}
#| label: comparison-alternatives-data
environment_comparison_levels <- c(
"Less harmful",
"Equally harmful",
"More harmful"
)
lifespan_comparison_levels <- c(
"Shorter lifespan",
"Similar lifespan",
"Greater lifespan"
)
environment_comparison_summary <- summarise_response_distribution(
df,
"Comparison_Environmental impact",
environment_comparison_levels
) |>
mutate(Comparison = "Environmental impact")
lifespan_comparison_summary <- summarise_response_distribution(
df,
"Comparison_Lifespan",
lifespan_comparison_levels
) |>
mutate(Comparison = "Lifespan")
alternative_comparison_summary <- bind_rows(
environment_comparison_summary,
lifespan_comparison_summary
)
q22_joint_summary <- df |>
filter(
!is.na(`Comparison_Environmental impact`),
!is.na(Comparison_Lifespan)
) |>
group_by(
Environmental_impact = `Comparison_Environmental impact`,
Lifespan = Comparison_Lifespan
) |>
summarise(
n = n(),
weighted_n = sum(analysis_weight),
.groups = "drop"
) |>
mutate(
pct = weighted_n / sum(weighted_n),
Environmental_impact = factor(
Environmental_impact,
levels = environment_comparison_levels
),
Lifespan = factor(
Lifespan,
levels = lifespan_comparison_levels
)
)
q22_joint_top <- q22_joint_summary |>
slice_max(pct, n = 1, with_ties = FALSE)
q22_joint_unfavourable_pct <- q22_joint_summary |>
filter(
Environmental_impact == "More harmful",
Lifespan == "Shorter lifespan"
) |>
pull(pct)
extract_alternative_comparison_proportion <- function(
comparison,
response
) {
alternative_comparison_summary |>
filter(
Comparison == comparison,
Response == response
) |>
pull(pct)
}
pct_environment_equal_or_less <-
extract_alternative_comparison_proportion(
"Environmental impact",
"Less harmful"
) +
extract_alternative_comparison_proportion(
"Environmental impact",
"Equally harmful"
)
pct_environment_more_harmful <-
extract_alternative_comparison_proportion(
"Environmental impact",
"More harmful"
)
pct_lifespan_shorter_alternative <-
extract_alternative_comparison_proportion(
"Lifespan",
"Shorter lifespan"
)
```
::: question
**Q22.** Compared to more expensive alternatives, you would say that small and inexpensive electronic devices tend to…
- **Q22a.** …be less harmful, equally harmful or more harmful to the environment?
- **Q22b.** …have a shorter, similar or greater lifespan?
:::
Most respondents (`r format_percent(pct_environment_equal_or_less)`) consider fast tech devices **equally or less harmful to the environment** than more expensive alternatives. Only `r format_percent(pct_environment_more_harmful)` perceive them as more harmful.
By contrast, `r format_percent(pct_lifespan_shorter_alternative)` expect fast tech devices to have a **shorter lifespan** than more expensive alternatives. Respondents therefore appear more conscious of a durability disadvantage than of a greater environmental impact.
```{r}
#| label: fig-comparison-alternatives
#| fig-cap: "Perceived environmental impact and lifespan compared with more expensive alternatives"
alternative_comparison_summary |>
mutate(
assessment = case_when(
Response %in% c(
"More harmful",
"Shorter lifespan"
) ~ "Less favourable",
Response %in% c(
"Equally harmful",
"Similar lifespan"
) ~ "Equivalent",
TRUE ~ "More favourable"
)
) |>
ggplot(aes(
x = pct,
y = fct_rev(Response),
fill = assessment
)) +
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(
"Less favourable" = bg_pink,
"Equivalent" = bg_ink_32,
"More favourable" = bg_accent
),
guide = "none"
) +
scale_x_continuous(
labels = percent_format(),
expand = expansion(mult = c(0, 0.16))
) +
facet_wrap(
~Comparison,
ncol = 1,
scales = "free_y"
) +
labs(
x = "% of respondents",
y = NULL
) +
theme(
panel.spacing.y = grid::unit(26, "pt")
)
```
The most frequent joint perception combines **`r str_to_lower(as.character(q22_joint_top$Environmental_impact))` environmental impact with a `r str_to_lower(as.character(q22_joint_top$Lifespan))` (`r format_percent(q22_joint_top$pct)`)**. Only `r format_percent(q22_joint_unfavourable_pct)` simultaneously perceive fast tech as more harmful and shorter-lived than more expensive alternatives.
Durability and environmental judgements overlap only partially.
```{r}
#| label: fig-q22-joint-heatmap
#| fig-cap: "Joint perceptions of environmental impact and lifespan relative to more expensive alternatives"
q22_joint_summary |>
ggplot(aes(
x = Lifespan,
y = Environmental_impact,
fill = pct
)) +
geom_tile(
colour = bg_surface,
linewidth = 1
) +
geom_text(
aes(label = percent(pct, accuracy = 0.1)),
colour = bg_ink,
size = bg_size_label / .pt
) +
scale_fill_bg_c(
palette = "seq",
labels = percent_format(),
name = "% of respondents"
) +
scale_x_discrete(
labels = \(x) str_wrap(x, width = 18)
) +
scale_y_discrete(
labels = \(x) str_wrap(x, width = 18)
) +
labs(x = "Perceived lifespan", y = "Perceived environmental impact") +
theme(
panel.grid = element_blank(),
legend.position = "top"
)
```
```{r}
#| label: fig-q22-joint-flow
#| fig-cap: "Flow between perceived environmental impact and lifespan relative to more expensive alternatives"
#| fig-height: 5.5
q22_joint_summary |>
mutate(
Environmental_impact_flow = factor(
str_replace_all(
as.character(Environmental_impact),
" ",
"\n"
),
levels = str_replace_all(
environment_comparison_levels,
" ",
"\n"
)
),
Lifespan_flow = factor(
str_replace_all(
as.character(Lifespan),
" ",
"\n"
),
levels = str_replace_all(
lifespan_comparison_levels,
" ",
"\n"
)
)
) |>
ggplot(
aes(
axis1 = Environmental_impact_flow,
axis2 = Lifespan_flow,
y = weighted_n
)
) +
ggalluvial::geom_alluvium(
aes(fill = Environmental_impact_flow),
width = 0.18,
alpha = 0.45,
knot.pos = 0.45
) +
ggalluvial::geom_stratum(
width = 0.18,
fill = bg_surface,
colour = bg_ink_32
) +
ggalluvial::stat_stratum(
geom = "text",
aes(label = after_stat(stratum)),
size = bg_size_label / .pt
) +
scale_fill_manual(
values = c(
"Less\nharmful" = bg_accent,
"Equally\nharmful" = bg_ink_32,
"More\nharmful" = bg_pink
),
guide = "none"
) +
scale_x_discrete(
limits = c("Environmental impact", "Lifespan"),
expand = expansion(mult = c(0.16, 0.16))
) +
scale_y_continuous(labels = NULL, breaks = NULL) +
labs(x = NULL, y = NULL) +
theme(panel.grid = element_blank())
```
------------------------------------------------------------------------
# Opinions, social norms & intentions
## Attitudes on fast tech
```{r}
#| label: attitude-buying-data
attitude_levels <- c(
"Completely unfavourable",
"Rather unfavourable",
"Neither favourable nor unfavourable",
"Rather favourable",
"Completely favourable"
)
attitude_summary <- summarise_response_distribution(
df,
"Attitude_buying",
attitude_levels
)
attitude_mean <- weighted_mean_safe(
df$Attitude_buying_recoded,
df$analysis_weight
)
pct_attitude_favourable <- weighted_mean_safe(
df$Attitude_buying_recoded >= 4,
df$analysis_weight
)
pct_attitude_unfavourable <- weighted_mean_safe(
df$Attitude_buying_recoded <= 2,
df$analysis_weight
)
```
::: question
**Q23a.** Regarding buying small and inexpensive electronic devices, you are…
:::
Attitudes towards buying fast tech are mainly neutral, with an average of **`r round(attitude_mean, 2)` on a five-point scale**. Overall, **`r format_percent(pct_attitude_favourable)` are rather or completely favourable**, compared with **`r format_percent(pct_attitude_unfavourable)` who are rather or completely unfavourable**.
```{r}
#| label: fig-attitude-buying
#| fig-cap: "Attitude towards buying fast tech"
attitude_summary |>
ggplot(aes(x = Response, 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.12))
) +
labs(x = NULL, y = "% of respondents") +
theme(
axis.text.x = element_text(angle = 25, hjust = 1)
)
```
## Social norms perception
### Injunctive norm
```{r}
#| label: injunctive-norm-data
injunctive_levels <- c(
"Completely disapprove",
"Rather disapprove",
"Neither approve nor disapprove",
"Rather approve",
"Completely approve"
)
injunctive_summary <- summarise_response_distribution(
df,
"Injunctive norm",
injunctive_levels
)
pct_norm_approve <- weighted_mean_safe(
df[["Injunctive norm_recoded"]] >= 4,
df$analysis_weight
)
pct_norm_disapprove <- weighted_mean_safe(
df[["Injunctive norm_recoded"]] <= 2,
df$analysis_weight
)
pct_norm_neutral <- weighted_mean_safe(
df[["Injunctive norm_recoded"]] == 3,
df$analysis_weight
)
```
::: question
**Q23b.** People important to you would…
:::
::: card-accent
[Key concept]{.eyebrow}\
An **injunctive norm** describes the approval or disapproval that people perceive from others, specifically those whose opinions matter to them.
:::
More than half of the respondents **(`r format_percent(pct_norm_neutral)`)** believe that important others would neither approve nor disapprove of buying fast tech. Approval is perceived by `r format_percent(pct_norm_approve)`, more than twice the share perceiving disapproval (`r format_percent(pct_norm_disapprove)`).
We can say that **buying fast tech is not perceived as something socially disapproved.**
```{r}
#| label: fig-injunctive-norm
#| fig-cap: "Perceived approval of fast tech purchasing by important others"
injunctive_summary |>
ggplot(aes(
x = pct,
y = fct_rev(Response)
)) +
geom_col(
width = bg_bar_width,
fill = bg_accent
) +
geom_text(
aes(label = percent(pct, accuracy = 0.1)),
hjust = -0.15,
size = bg_size_label / .pt
) +
scale_x_continuous(
labels = percent_format(),
expand = expansion(mult = c(0, 0.16))
) +
scale_y_discrete(
labels = \(x) str_wrap(x, width = 34)
) +
labs(
x = "% of respondents",
y = NULL
)
```
### Dynamic norm
```{r}
#| label: dynamic-norm-data
dynamic_levels <- c(
"Far fewer people",
"Fewer people",
"The same number",
"More people",
"Far more people"
)
dynamic_summary <- summarise_response_distribution(
df,
"Dynamic norm",
dynamic_levels
)
pct_norm_more <- weighted_mean_safe(
df[["Dynamic norm_recoded"]] >= 1,
df$analysis_weight
)
pct_norm_fewer <- weighted_mean_safe(
df[["Dynamic norm_recoded"]] <= -1,
df$analysis_weight
)
pct_norm_equal <- weighted_mean_safe(
df[["Dynamic norm_recoded"]] == 0,
df$analysis_weight
)
```
::: question
**Q24.** Do you think that more or fewer people buy small and inexpensive electronic devices over time?
:::
::: card-accent
[Key concept]{.eyebrow}\
A **dynamic norm** describes how people perceive a behaviour to be changing over time. In our case, the evolution of people buying fast tech devices.
:::
Almost half of respondents (`r format_percent(pct_norm_more)`) believe that more or far more people are buying fast tech, while `r format_percent(pct_norm_equal)` perceive no change and `r format_percent(pct_norm_fewer)` perceive a decline.
```{r}
#| label: fig-dynamic-norm
#| fig-cap: "Perceived change in fast tech purchasing over time"
dynamic_summary |>
ggplot(aes(
x = pct,
y = fct_rev(Response)
)) +
geom_col(
width = bg_bar_width,
fill = bg_accent
) +
geom_text(
aes(label = percent(pct, accuracy = 0.1)),
hjust = -0.15,
size = bg_size_label / .pt
) +
scale_x_continuous(
labels = percent_format(),
expand = expansion(mult = c(0, 0.16))
) +
scale_y_discrete(
labels = \(x) str_wrap(x, width = 34)
) +
labs(
x = "% of respondents",
y = NULL
)
```
## Buying intentions
```{r}
#| label: future-buying-intention-data
future_intention_summary <- summarise_response_distribution(
df,
"12months_Intentionbuy",
future_purchase_intention_levels
)
pct_intend_more <- future_intention_summary |>
filter(Response %in% c("Much more", "More")) |>
summarise(pct = sum(pct)) |>
pull(pct)
pct_intend_less <- future_intention_summary |>
filter(Response %in% c(
"Less", "Much less", "I intend to stop"
)) |>
summarise(pct = sum(pct)) |>
pull(pct)
pct_not_intend_reduce <- future_intention_summary |>
filter(Response %in% c(
"The same",
"More",
"Much more"
)) |>
summarise(pct = sum(pct)) |>
pull(pct)
```
::: question
**Q25.** Over the next 12 months, do you intend to buy more, fewer or the same number of small and inexpensive electronic devices?
:::
Most respondents (**`r format_percent(future_intention_summary$pct[future_intention_summary$Response == "The same"])`**) expect to buy the same number of fast tech products during the next 12 months. About a tenth (**`r format_percent(pct_intend_more)`**) intend to buy more or much more, while **`r format_percent(pct_intend_less)`** intend to buy less, much less or stop altogether.
Put differently, **`r format_percent(pct_not_intend_reduce)` don't intend to reduce their fast tech consumption**, as they expect to buy the same number, more or much more over the next 12 months.
```{r}
#| label: fig-future-buying-intention
#| fig-cap: "Intended change in fast tech purchases over the next 12 months"
future_intention_summary |>
mutate(
response_type = if_else(
as.character(Response) == "I intend to stop",
"Stop",
"Other responses"
),
Response = factor(
as.character(Response),
levels = future_purchase_intention_levels
)
) |>
ggplot(aes(
x = Response,
y = pct,
fill = response_type
)) +
geom_col(width = bg_bar_width) +
geom_text(
aes(label = percent(pct, accuracy = 0.1)),
vjust = -0.4,
size = bg_size_label / .pt
) +
scale_fill_manual(
values = c(
"Other responses" = bg_accent,
"Stop" = bg_ink_32
),
guide = "none"
) +
scale_y_continuous(
labels = percent_format(),
expand = expansion(mult = c(0, 0.12))
) +
labs(
x = NULL,
y = "% of respondents"
) +
theme(
axis.text.x = element_text(
angle = 25,
hjust = 1
)
)
```
## Views on consumption
```{r}
#| label: consumer-consumption-view-data
agreement_levels <- c(
"I completely disagree",
"I disagree",
"I neither agree nor disagree",
"I agree",
"I completely agree"
)
consumer_view_summary <- summarise_response_distribution(
df,
"Consumers should buy fewer",
agreement_levels
)
pct_consumers_agree <- weighted_mean_safe(
df[["Consumers should buy fewer_recoded"]] >= 4,
df$analysis_weight
)
pct_consumers_disagree <- weighted_mean_safe(
df[["Consumers should buy fewer_recoded"]] <= 2,
df$analysis_weight
)
```
::: question
**Q26a.** What do you think about the following statement? “Consumers should buy fewer small and inexpensive electronic devices.”
:::
A short majority of respondents don't have a strong opinion on the matter, and **`r format_percent(pct_consumers_agree)` agree or completely agree that consumers should buy fewer devices**. Only `r format_percent(pct_consumers_disagree)` disagree or completely disagree.
```{r}
#| label: fig-consumers-buy-fewer
#| fig-cap: "Agreement that consumers should buy fewer fast tech devices"
consumer_view_summary |>
ggplot(aes(x = Response, 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.12))
) +
labs(x = NULL, y = "% of respondents") +
theme(
axis.text.x = element_text(angle = 25, hjust = 1)
)
```
## Government regulation over fast tech
```{r}
#| label: government-regulation-data
government_view_summary <- summarise_response_distribution(
df,
"Governments should more strictly regulate",
agreement_levels
)
pct_government_agree <- weighted_mean_safe(
df[["Governments should more strictly regulate_recoded"]] >= 4,
df$analysis_weight
)
pct_government_disagree <- weighted_mean_safe(
df[["Governments should more strictly regulate_recoded"]] <= 2,
df$analysis_weight
)
```
::: question
**Q26b.** What do you think about the following statement? “Governments should more strictly regulate the sale of small and inexpensive electronic devices.”
:::
Opinions regarding stricter government regulation are divided. `r format_percent(pct_government_agree)` agree or completely agree, compared with `r format_percent(pct_government_disagree)` who disagree or completely disagree. The remaining respondents remain neutral.
```{r}
#| label: fig-government-regulation
#| fig-cap: "Agreement with stricter government regulation of fast tech sales"
government_view_summary |>
ggplot(aes(x = Response, 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.12))
) +
labs(x = NULL, y = "% of respondents") +
theme(
axis.text.x = element_text(angle = 25, hjust = 1)
)
```
------------------------------------------------------------------------
# Knowledge & Awareness
## Awareness of platform financial contribution requirements
```{r}
#| label: platform-awareness-data
platform_awareness_levels <- c(
"Yes, I knew this",
"I heard of it but didn’t know the details",
"No, I didn’t know this"
)
platform_awareness_summary <- df |>
filter(!is.na(`Online plateforms obligations`)) |>
group_by(Response = `Online plateforms obligations`) |>
summarise(
n = n(),
weighted_n = sum(analysis_weight),
.groups = "drop"
) |>
mutate(
Response = factor(
Response,
levels = platform_awareness_levels
),
pct = weighted_n / sum(weighted_n)
) |>
arrange(Response)
```
::: question
**Q27.** Did you know that online platforms selling electronic devices are legally required to contribute financially to the collection and recycling of electronic waste?
:::
Only **`r format_percent(platform_awareness_summary$pct[platform_awareness_summary$Response == "Yes, I knew this"])` knew about the requirement**, while `r format_percent(platform_awareness_summary$pct[platform_awareness_summary$Response == "I heard of it but didn’t know the details"])` had heard of it without knowing the details. **More than half (`r format_percent(platform_awareness_summary$pct[platform_awareness_summary$Response == "No, I didn’t know this"])`) were unaware**.
```{r}
#| label: fig-platform-awareness
#| fig-cap: "Awareness of online platforms’ financial contribution requirements"
platform_awareness_summary |>
mutate(Response_plot = str_wrap(as.character(Response), 38)) |>
ggplot(aes(
x = pct,
y = fct_reorder(Response_plot, pct)
)) +
geom_col(width = bg_bar_width, fill = bg_accent) +
geom_text(
aes(label = percent(pct, accuracy = 0.1)),
hjust = -0.15,
size = bg_size_label / .pt
) +
scale_x_continuous(
labels = percent_format(),
expand = expansion(mult = c(0, 0.16))
) +
labs(x = "% of respondents", y = NULL)
```
## Awareness that fast tech contains electronics
```{r}
#| label: electronic-parts-awareness-data
electronic_awareness_col <- names(df)[
str_detect(
names(df),
"^Before taking this questionnaire, were you aware"
)
]
electronic_awareness_summary <- df |>
transmute(
Response = .data[[electronic_awareness_col]],
analysis_weight
) |>
filter(!is.na(Response)) |>
group_by(Response) |>
summarise(
n = n(),
weighted_n = sum(analysis_weight),
.groups = "drop"
) |>
mutate(
Response = factor(Response, levels = c("Yes", "No")),
pct = weighted_n / sum(weighted_n)
) |>
arrange(Response)
```
::: question
**Q28.** Before taking this questionnaire, were you aware that these small and inexpensive electronic devices contain electronic parts?
:::
Only `r format_percent(electronic_awareness_summary$pct[electronic_awareness_summary$Response == "No"])` were not aware that fast tech devices contain electronic parts, before completing the questionnaire.
```{r}
#| label: fig-electronic-parts-awareness
#| fig-cap: "Awareness that fast tech devices contain electronic parts"
electronic_awareness_summary |>
ggplot(aes(x = Response, 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.12))
) +
labs(x = NULL, y = "% of respondents")
```
------------------------------------------------------------------------
7.2 Social norms perception
7.2.1 Injunctive norm
Show R code
Q23b. People important to you would…
Key concept
An injunctive norm describes the approval or disapproval that people perceive from others, specifically those whose opinions matter to them.
More than half of the respondents (51.0%) believe that important others would neither approve nor disapprove of buying fast tech. Approval is perceived by 35.3%, more than twice the share perceiving disapproval (13.7%).
We can say that buying fast tech is not perceived as something socially disapproved.
Show R code
7.2.2 Dynamic norm
Show R code
Q24. Do you think that more or fewer people buy small and inexpensive electronic devices over time?
Key concept
A dynamic norm describes how people perceive a behaviour to be changing over time. In our case, the evolution of people buying fast tech devices.
Almost half of respondents (46.2%) believe that more or far more people are buying fast tech, while 39.7% perceive no change and 14.1% perceive a decline.
Show R code