HIV self-testing positivity rate and linkage to confirmatory testing and care: a telephone survey in Côte d’Ivoire, Mali and Senegal

Author

Arsène Kra Kouassi et al.

Published

June 9, 2023

Code
library(tidyverse)
library(gtsummary)
library(labelled)
library(scales)
library(utils)
data <- readr::read_csv("data.csv", show_col_types = FALSE) |> 
  set_variable_labels(
    country = "Country",
    sex = "Sex",
    age_group = "Age group",
    marital_status = "Marital status",
    educational_level = "Educational level",
    distribution_channel = "HIVST distribution channel",
    first_time_tester = "Firt-time tester",
    HIVST_reported_lines = "Reported number of visibles lines on the HIVST kit",
    HIVST_reported_result = "Reported self-interpreted result of the HIVST",
    date_phase1 = "Date when phase 1 questionnaire was completed",
    recontact_phase2 = "Accpeted to be recontacted for phase 2 survey?",
    status_phase2 = "Final status for participation in phase 2 survey",
    date_phase2 = "Date when phase 2 questionnaire was completed",
    status_phase_1and2 = "Final participation status for phase 1 and phase 2",
    confirmatory_test = "Did participant link to confirmatory testing?",
    reason_non_confirmatory_test = "If did not link to confirmatory testing, main reported reason",
    time_to_confirmation = "Reported time between HIVST and confirmatory testing",
    place_confirmatory_test = "Place of confirmatory testing",
    confirmatory_test_result = "Result of confirmatory testing",
    consulted_health_prof = "If diagnosed HIV positive, consulted a professionnal healthcare?",
    iniated_ART = "If diagnosed HIV positive, initiated antiretroviral treatment"
  )

Table 1. Self-reported test result and the reported number of lines among participants of phase 1, and positivity rates according to different hypotheses

Code
data <- data |>
  mutate(
    HIVST_detailed_result =
      case_when(
        (HIVST_reported_lines == "2 lines" & HIVST_reported_result == "reactive") ~ "2 lines / reactive",
        (HIVST_reported_lines == "2 lines" & HIVST_reported_result == "non reactive") ~ "2 lines / non-reactive",
        (HIVST_reported_lines == "2 lines" & (HIVST_reported_result == "DK" | HIVST_reported_result == "R")) ~ "2 lines / DK-R",
        (HIVST_reported_lines == "1 line" & HIVST_reported_result == "reactive") ~ "1 line / reactive",
        (HIVST_reported_lines == "1 line" & HIVST_reported_result == "non reactive") ~ "1 line / non-reactive",
        (HIVST_reported_lines == "1 line" & (HIVST_reported_result == "DK" | HIVST_reported_result == "R")) ~ "1 line / DK-R",
        (HIVST_reported_lines == "0 line" & HIVST_reported_result == "non reactive") ~ "0 line / non-reactive",
        (HIVST_reported_lines == "0 line" & HIVST_reported_result == "reactive") ~ "0 line / reactive",
        (HIVST_reported_lines == "0 line" & (HIVST_reported_result == "DK" | HIVST_reported_result == "R")) ~ "0 line / DK-R",
        ((HIVST_reported_lines == "0 line" | HIVST_reported_lines == "1 line") & HIVST_reported_result == "invalid") ~ "0-1 line / invalid",
        (HIVST_reported_lines == "2 lines" & HIVST_reported_result == "invalid") ~ "2 lines / invalid",
        ((HIVST_reported_lines == "DK" | HIVST_reported_lines == "R") & HIVST_reported_result == "invalid") ~ "DK-R / invalid",
        ((HIVST_reported_lines == "DK" | HIVST_reported_lines == "R") & HIVST_reported_result == "reactive") ~ "DK-R / reactive",
        ((HIVST_reported_lines == "DK" | HIVST_reported_lines == "R") & HIVST_reported_result == "non reactive") ~ "DK-R / non-reactive",
        ((HIVST_reported_lines == "DK" | HIVST_reported_lines == "R") & (HIVST_reported_result == "DK" | HIVST_reported_result == "R")) ~ "DK-R / DK-R"
      ),
     HIVST_detailed_result = HIVST_detailed_result |> 
      fct_relevel(
        "2 lines / reactive", "1 line / non-reactive", "0-1 line / invalid",
        "1 line / reactive", "2 lines / non-reactive", "0 line / non-reactive",
        "0 line / DK-R", "1 line / DK-R", "2 lines / DK-R", "DK-R / reactive",
        "DK-R / DK-R", "DK-R / non-reactive"
      )
  ) |>
  set_variable_labels(HIVST_detailed_result = "Reported number of lines / self-interpreted HIVST result")

tbl1 <-
  data |>
  tbl_summary(
    include = HIVST_detailed_result,
    label = HIVST_detailed_result ~ ""
  ) |>
  modify_header(label = "**Phase 1 participants**") |>
  as_gt() |>
  gt::tab_row_group(
    label = gt::md("Partial reponse (P)*"),
    rows = 8:13
  ) |>
  gt::tab_row_group(
    label = gt::md("*Inconsistant reponse (I)*"),
    rows = 5:7
  ) |>
  gt::tab_row_group(
    label = gt::md("*Consistant reponse (C)*"),
    rows = 2:4
  )

tbl1
Phase 1 participants N = 2,6151
Consistant reponse (C)
    2 lines / reactive 50 (1.9%)
    1 line / non-reactive 2,292 (88%)
    0-1 line / invalid 4 (0.2%)
Inconsistant reponse (I)
    1 line / reactive 10 (0.4%)
    2 lines / non-reactive 35 (1.3%)
    0 line / non-reactive 3 (0.1%)
Partial reponse (P)*
    0 line / DK-R 1 (<0.1%)
    1 line / DK-R 117 (4.5%)
    2 lines / DK-R 29 (1.1%)
    DK-R / reactive 2 (<0.1%)
    DK-R / DK-R 28 (1.1%)
    DK-R / non-reactive 44 (1.7%)
1 n (%)

Table 2.a: Positivity rates based on self-interpreted HIVST result, by distribution channel, gender and country, among phase 1 participants

Code
data <- data |>
  mutate(
    channel_by_sex = interaction(sex, distribution_channel) |>
      fct_recode() |>
      fct_relevel(
        "man.MSM-based channels", "woman.MSM-based channels", "man.FSW-based channels",
        "woman.FSW-based channels", "man.Other delivery channels", "woman.Other delivery channels"
      )
  ) |> 
  set_variable_labels(channel_by_sex = "Distribution channel by sex")

tbl2a_low <- data |>
  to_factor() |>
  tbl_custom_summary(
    include = c(country),
    by = channel_by_sex,
    stat_fns = ~ proportion_summary(variable = "HIVST_reported_result", value = c("reactive")),
    statistic = ~"{prop}% ({n}/{N})",
    digits = ~ list(
      function(x) {
        style_percent(x, digits = 0)
      }, 0, 0
    ),
    overall_row = TRUE
  ) |>
  add_overall(last = FALSE)

tbl2a_central <- data |>
  filter(HIVST_reported_result != "DK", HIVST_reported_result != "R") |>
  to_factor() |>
  tbl_custom_summary(
    include = c(country),
    by = channel_by_sex,
    stat_fns = ~ proportion_summary(variable = "HIVST_reported_result", value = c("reactive")),
    statistic = ~"{prop}% ({n}/{N})",
    digits = ~ list(
      function(x) {
        style_percent(x, digits = 0)
      }, 0, 0
    ),
    overall_row = TRUE
  ) |>
  add_overall(last = FALSE)

tbl2a_high <- data |>
  to_factor() |>
  tbl_custom_summary(
    include = c(country),
    by = channel_by_sex,
    stat_fns = ~ proportion_summary(variable = "HIVST_reported_result", value = c("reactive", "DK", "R")),
    statistic = ~"{prop}% ({n}/{N})",
    digits = ~ list(
      function(x) {
        style_percent(x, digits = 0)
      }, 0, 0
    ),
    overall_row = TRUE
  ) |>
  add_overall(last = FALSE)

tbl2a <- tbl_stack(
  list(tbl2a_low, tbl2a_central, tbl2a_high),
  group_header = c(
    "Low: positivity rate based on self reported test result and DK-R are considered not reactive",
    "Central: positivity rate based on self reported test result and DK-R are excluded",
    "High: positivity rate based on self reported test result and DK-R are considered reactive"
  )
)

tbl2a |>
  modify_header(label ~ "**Variable**") |>
  modify_spanning_header(
    c("stat_1", "stat_2") ~ "**MSM-based channels**",
    c("stat_3", "stat_4") ~ "**FSW-based channels**",
    c("stat_5", "stat_6") ~ "**Others delivery channels**",
    stat_0 ~ "**Total**"
  ) |>
  modify_header(
    stat_1 ~ "**Man**", stat_2 ~ "**Woman**",
    stat_3 ~ "**Man**", stat_4 ~ "**Woman**",
    stat_5 ~ "**Man**", stat_6 ~ "**Woman**",
    stat_0 ~ " "
  ) |>
  modify_footnote(update = everything() ~ NA)
Variable Total MSM-based channels FSW-based channels Others delivery channels
Man Woman Man Woman Man Woman
Low: positivity rate based on self reported test result and DK-R are considered not reactive
Overall 2.4% (62/2,615) 3.2% (32/997) 1.0% (1/103) 1.6% (10/620) 2.5% (17/685) 0.7% (1/137) 1.4% (1/73)
Country
    Côte d'Ivoire 1.8% (25/1,390) 2.5% (16/650) 1.4% (1/73) 1.5% (5/339) 1.2% (3/245) 0% (0/60) 0% (0/23)
    Mali 3.5% (34/984) 4.6% (14/306) 0% (0/29) 1.9% (5/269) 3.9% (14/360) 9.1% (1/11) 0% (0/9)
    Senegal 1.2% (3/241) 4.9% (2/41) 0% (0/1) 0% (0/12) 0% (0/80) 0% (0/66) 2.4% (1/41)
Central: positivity rate based on self reported test result and DK-R are excluded
Overall 2.5% (62/2,440) 3.4% (32/931) 1.0% (1/101) 1.7% (10/579) 2.7% (17/631) 0.8% (1/130) 1.5% (1/68)
Country
    Côte d'Ivoire 2.0% (25/1,279) 2.7% (16/597) 1.4% (1/71) 1.6% (5/311) 1.4% (3/221) 0% (0/58) 0% (0/21)
    Mali 3.6% (34/952) 4.7% (14/301) 0% (0/29) 1.9% (5/257) 4.1% (14/345) 9.1% (1/11) 0% (0/9)
    Senegal 1.4% (3/209) 6.1% (2/33) 0% (0/1) 0% (0/11) 0% (0/65) 0% (0/61) 2.6% (1/38)
High: positivity rate based on self reported test result and DK-R are considered reactive
Overall 9.1% (237/2,615) 9.8% (98/997) 2.9% (3/103) 8.2% (51/620) 10% (71/685) 5.8% (8/137) 8.2% (6/73)
Country
    Côte d'Ivoire 9.8% (136/1,390) 11% (69/650) 4.1% (3/73) 9.7% (33/339) 11% (27/245) 3.3% (2/60) 8.7% (2/23)
    Mali 6.7% (66/984) 6.2% (19/306) 0% (0/29) 6.3% (17/269) 8.1% (29/360) 9.1% (1/11) 0% (0/9)
    Senegal 15% (35/241) 24% (10/41) 0% (0/1) 8.3% (1/12) 19% (15/80) 7.6% (5/66) 9.8% (4/41)

Table 2.b: Positivity rates based on the reported number of lines, by distribution channel, gender and country, among phase 1 participants

Code
tbl2b_low <- data |>
  to_factor() |>
  tbl_custom_summary(
    include = c(country),
    by = channel_by_sex,
    stat_fns = ~ proportion_summary(variable = "HIVST_reported_lines", value = c("2 lines")),
    statistic = ~"{prop}% ({n}/{N})",
    digits = ~ list(
      function(x) {
        style_percent(x, digits = 0)
      }, 0, 0
    ),
    overall_row = TRUE
  ) |>
  add_overall(last = FALSE)


tbl2b_central <- data |>
  filter(HIVST_reported_lines != "DK", HIVST_reported_lines != "R") |>
  to_factor() |>
  tbl_custom_summary(
    include = c(country),
    by = channel_by_sex,
    stat_fns = ~ proportion_summary(variable = "HIVST_reported_lines", value = c("2 lines")),
    statistic = ~"{prop}% ({n}/{N})",
    digits = ~ list(
      function(x) {
        style_percent(x, digits = 0)
      }, 0, 0
    ),
    overall_row = TRUE
  ) |>
  add_overall(last = FALSE)


tbl2b_high <- data |>
  to_factor() |>
  tbl_custom_summary(
    include = c(country),
    by = channel_by_sex,
    stat_fns = ~ proportion_summary(variable = "HIVST_reported_lines", value = c("2 lines", "DK", "R")),
    statistic = ~"{prop}% ({n}/{N})",
    digits = ~ list(
      function(x) {
        style_percent(x, digits = 0)
      }, 0, 0
    ),
    overall_row = TRUE
  ) |>
  add_overall(last = FALSE)



tbl2b <- tbl_stack(list(tbl2b_low, tbl2b_central, tbl2b_high),
  group_header = c(
    "Low: positivity rate based on self reported number of lines and DK-R are considered not 2 lines",
    "Central: positivity rate based on self reported number of lines and DK-R are excluded",
    "High: positivity rate based on self reported number of lines and DK-R are considered 2 lines"
  )
)

tbl2b |>
  modify_header(label ~ "**Variable**") |>
  modify_spanning_header(
    c("stat_1", "stat_2") ~ "**MSM-based channels**",
    c("stat_3", "stat_4") ~ "**FSW-based channels**",
    c("stat_5", "stat_6") ~ "**Others delivery channels**",
    stat_0 ~ "**Total**"
  ) |>
  modify_header(
    stat_1 ~ "**Man**", stat_2 ~ "**Woman**",
    stat_3 ~ "**Man**", stat_4 ~ "**Woman**",
    stat_5 ~ "**Man**", stat_6 ~ "**Woman**",
    stat_0 ~ " "
  ) |>
  modify_footnote(update = everything() ~ NA)
Variable Total MSM-based channels FSW-based channels Others delivery channels
Man Woman Man Woman Man Woman
Low: positivity rate based on self reported number of lines and DK-R are considered not 2 lines
Overall 4.4% (114/2,615) 4.7% (47/997) 4.9% (5/103) 4.5% (28/620) 4.1% (28/685) 2.9% (4/137) 2.7% (2/73)
Country
    Côte d'Ivoire 3.8% (53/1,390) 4.2% (27/650) 5.5% (4/73) 4.7% (16/339) 2.0% (5/245) 0% (0/60) 4.3% (1/23)
    Mali 4.9% (48/984) 4.9% (15/306) 3.4% (1/29) 4.5% (12/269) 5.3% (19/360) 9.1% (1/11) 0% (0/9)
    Senegal 5.4% (13/241) 12% (5/41) 0% (0/1) 0% (0/12) 5.0% (4/80) 4.5% (3/66) 2.4% (1/41)
Central: positivity rate based on self reported number of lines and DK-R are excluded
Overall 4.5% (114/2,541) 4.8% (47/977) 4.9% (5/103) 4.6% (28/605) 4.2% (28/660) 3.1% (4/128) 2.9% (2/68)
Country
    Côte d'Ivoire 3.9% (53/1,368) 4.2% (27/641) 5.5% (4/73) 4.8% (16/331) 2.1% (5/241) 0% (0/60) 4.5% (1/22)
    Mali 5.0% (48/955) 5.0% (15/298) 3.4% (1/29) 4.5% (12/264) 5.5% (19/344) 9.1% (1/11) 0% (0/9)
    Senegal 6.0% (13/218) 13% (5/38) 0% (0/1) 0% (0/10) 5.3% (4/75) 5.3% (3/57) 2.7% (1/37)
High: positivity rate based on self reported number of lines and DK-R are considered 2 lines
Overall 7.2% (188/2,615) 6.7% (67/997) 4.9% (5/103) 6.9% (43/620) 7.7% (53/685) 9.5% (13/137) 9.6% (7/73)
Country
    Côte d'Ivoire 5.4% (75/1,390) 5.5% (36/650) 5.5% (4/73) 7.1% (24/339) 3.7% (9/245) 0% (0/60) 8.7% (2/23)
    Mali 7.8% (77/984) 7.5% (23/306) 3.4% (1/29) 6.3% (17/269) 9.7% (35/360) 9.1% (1/11) 0% (0/9)
    Senegal 15% (36/241) 20% (8/41) 0% (0/1) 17% (2/12) 11% (9/80) 18% (12/66) 12% (5/41)

Table 3. Linkage to confirmatory testing, proportion being confirmed HIV positive and treatment initiation, by reported number of lines and self-interpreted HIVST result among phase 2 eligible participants who completed their questionnaire

Code
dat <- data |>
  filter(
    status_phase2 == "questionnaires completed",
    HIVST_reported_result == "reactive" | HIVST_reported_lines == "2 lines",
    recontact_phase2 == "yes"
  ) |>
  mutate(all = "ALL")
dat$HIVST_detailed_result <- droplevels(dat$HIVST_detailed_result)

tbl_completed <-
  dat |>
  tbl_summary(
    include = c(all, HIVST_detailed_result),
    statistic = ~"{n}"
  ) |>
  modify_header(stat_0 = "**n**") |>
  modify_footnote(update = everything() ~ NA)

tbl_linked <-
  dat |>
  tbl_summary(
    by = confirmatory_test,
    include = c(all, HIVST_detailed_result),
    percent = "row",
    digits = ~0
  ) |>
  add_ci(style_fun = ~ label_percent(accuracy = 1, suffix = "")) |>
  modify_column_hide(c(stat_1, ci_stat_1)) |>
  modify_header(stat_2 ~ "**n (%)**") |>
  modify_footnote(update = everything() ~ NA)

tbl_confirmed <-
  dat |>
  filter(confirmatory_test == "yes") |>
  mutate(confirmed = confirmatory_test_result == "positive") |>
  tbl_summary(
    by = confirmed,
    include = c(all, HIVST_detailed_result),
    percent = "row",
    digits = ~0
  ) |>
  add_ci(style_fun = ~ label_percent(accuracy = 1, suffix = "")) |>
  modify_column_hide(c(stat_1, ci_stat_1)) |>
  modify_header(stat_2 ~ "**n (%)**") |>
  modify_footnote(update = everything() ~ NA)

tbl_initiated <-
  dat |>
  filter(confirmatory_test_result == "positive") |>
  mutate(initiated = consulted_health_prof == "yes") |>
  mutate(HIVST_detailed_result = fct_drop(HIVST_detailed_result)) |>
  tbl_summary(
    by = initiated,
    include = c(all, HIVST_detailed_result),
    percent = "row",
    digits = ~0
  ) |>
  add_ci(style_fun = ~ label_percent(accuracy = 1, suffix = "")) |>
  modify_column_hide(c(stat_1, ci_stat_1)) |>
  modify_header(stat_2 ~ "**n (%)**") |>
  modify_footnote(update = everything() ~ NA)


tbl_merge(
  list(tbl_completed, tbl_linked, tbl_confirmed, tbl_initiated),
  tab_spanner = c(
    "**Completed phase 2**",
    "**Linked to confirmatory testing**",
    "**Confirmed HIV positive**",
    "**Initiated ART**"
  )
)
Characteristic Completed phase 2 Linked to confirmatory testing Confirmed HIV positive Initiated ART
n n (%) 95% CI1 n (%) 95% CI1 n (%) 95% CI1
all
    ALL 78 34 (44%) 33%, 55% 19 (56%) 38%, 72% 18 (95%) 72%, 100%
HIVST_detailed_result
    2 lines / reactive 27 15 (56%) 36%, 74% 12 (80%) 51%, 95% 12 (100%) 70%, 100%
    1 line / reactive 7 1 (14%) 1%, 58% 0 (0%) 0%, 95%
    2 lines / non-reactive 25 9 (36%) 19%, 57% 3 (33%) 9%, 69% 3 (100%) 31%, 100%
    2 lines / DK-R 18 8 (44%) 22%, 69% 4 (50%) 22%, 78% 3 (75%) 22%, 99%
    DK-R / reactive 1 1 (100%) 5%, 100% 0 (0%) 0%, 95%
1 CI = Confidence Interval

Figure 3: Flow chart of the participant selection process for Phase 2 of the survey

Code
n_eligible_for_phase_2 <- data |>
  filter((HIVST_reported_result == "reactive" | HIVST_reported_lines == "2 lines")) |>
  nrow()

n_eligible_agreed_recontacted <- data |>
  filter((HIVST_reported_result == "reactive" | HIVST_reported_lines == "2 lines") & (recontact_phase2 == "yes")) |>
  nrow()

n_eligible_refusal_recontacted <- data |>
  filter((HIVST_reported_result == "reactive" | HIVST_reported_lines == "2 lines") & (recontact_phase2 == "no")) |>
  nrow()

n_unreachable_time_phase2 <- data |>
  filter((HIVST_reported_result == "reactive" | HIVST_reported_lines == "2 lines") & (recontact_phase2 == "yes") & (status_phase2 == "unavaible" | is.na(status_phase2))) |>
  nrow()

n_successfully_recontacted <- data |>
  filter((HIVST_reported_result == "reactive" | HIVST_reported_lines == "2 lines") & (recontact_phase2 == "yes") & (status_phase2 != "unavaible" & !is.na(status_phase2))) |>
  nrow()

n_refused_partcipate <- data |>
  filter((HIVST_reported_result == "reactive" | HIVST_reported_lines == "2 lines") & (recontact_phase2 == "yes") & (status_phase2 != "unavaible" & !is.na(status_phase2)) & status_phase2 == "refusal") |>
  nrow()

n_accepted_partcipate <- data |>
  filter((HIVST_reported_result == "reactive" | HIVST_reported_lines == "2 lines") & (recontact_phase2 == "yes") & (status_phase2 != "unavaible" & !is.na(status_phase2)) & status_phase2 != "refusal") |>
  nrow()

n_disconneted <- data |>
  filter((HIVST_reported_result == "reactive" | HIVST_reported_lines == "2 lines") & (recontact_phase2 == "yes") & (status_phase2 != "unavaible" & !is.na(status_phase2)) & (status_phase2 != "refusal" & status_phase2 == "disconnected")) |>
  nrow()

n_dropped <- data |>
  filter((HIVST_reported_result == "reactive" | HIVST_reported_lines == "2 lines") & (recontact_phase2 == "yes") & (status_phase2 != "unavaible" & !is.na(status_phase2)) & status_phase2 != "refusal" & status_phase2 == "dropped out before the end") |>
  nrow()

n_completed_quest_phase2 <- data |>
  filter((HIVST_reported_result == "reactive" | HIVST_reported_lines == "2 lines") & (recontact_phase2 == "yes") & status_phase2 == "questionnaires completed") |>
  nrow()
  • 126 participants who reported a reactive test and/or two lines in phase 1

  • 120 participants who agreed to be recalled several months later

  • 6 participants refusal to be recalled several months later

  • 24 unreachable at the time of phase 2

  • 96 successfully recontacted for phase 2

  • 7 refused to participate

  • 89 accepted to participate in phase 2 survey

  • 1 disconnected and unreachable

  • 10 dropped out before the end

  • 78 completed questionnaire phase 2

Table S1. Eligibility and participation in phase 2 survey by sociodemographic characteristics, distribution channel, HIV testing history, the reported number of lines and the self-interpreted HIVST result

Code
data <- data |>
  mutate(
    marital_status = marital_status |>
      fct_relevel(
        "single", "divorced / separated / widowed", "living with partner / married"
      ),
    educational_level = educational_level |>
      fct_relevel(
        "none / primary", "secondary", "higher"
      )
  )

data |>
  tbl_summary(
    include =
      c(
        country, distribution_channel, age_group,
        marital_status, educational_level, first_time_tester, HIVST_detailed_result
      ),
    by = status_phase_1and2,
    type = list(c(first_time_tester) ~ "categorical")
  ) |>
  add_overall() |>
  add_p(
    test = list(
      HIVST_detailed_result ~ "chisq.test",
      distribution_channel ~ "chisq.test"
    )
  )
Characteristic Overall, N = 2,6151 completed phase 2 questionnaire, N = 781 eligible for phase 2 but did not complete the questionnaire, N = 421 phase 1 participants not eligible for phase 2, N = 2,4951 p-value2
Country 0.9
    Côte d'Ivoire 1,390 (53%) 39 (50%) 20 (48%) 1,331 (53%)
    Mali 984 (38%) 31 (40%) 18 (43%) 935 (37%)
    Senegal 241 (9.2%) 8 (10%) 4 (9.5%) 229 (9.2%)
HIVST distribution channel 0.2
    FSW-based channels 1,305 (50%) 36 (46%) 25 (60%) 1,244 (50%)
    MSM-based channels 1,100 (42%) 40 (51%) 14 (33%) 1,046 (42%)
    Other delivery channels 210 (8.0%) 2 (2.6%) 3 (7.1%) 205 (8.2%)
Age group 0.5
    24 years or less 1,164 (45%) 27 (35%) 20 (48%) 1,117 (45%)
    25-34 years 1,063 (41%) 38 (49%) 16 (38%) 1,009 (40%)
    35 years or more 388 (15%) 13 (17%) 6 (14%) 369 (15%)
marital_status 0.3
    single 1,761 (67%) 54 (69%) 28 (67%) 1,679 (67%)
    divorced / separated / widowed 97 (3.7%) 6 (7.7%) 2 (4.8%) 89 (3.6%)
    living with partner / married 757 (29%) 18 (23%) 12 (29%) 727 (29%)
educational_level 0.057
    none / primary 503 (19%) 13 (17%) 10 (24%) 480 (19%)
    secondary 1,432 (55%) 50 (64%) 28 (67%) 1,354 (54%)
    higher 680 (26%) 15 (19%) 4 (9.5%) 661 (26%)
Firt-time tester 0.3
    no 1,537 (59%) 40 (51%) 22 (52%) 1,475 (59%)
    yes 1,078 (41%) 38 (49%) 20 (48%) 1,020 (41%)
Reported number of lines / self-interpreted HIVST result <0.001
    2 lines / reactive 50 (1.9%) 27 (35%) 20 (48%) 3 (0.1%)
    1 line / non-reactive 2,292 (88%) 0 (0%) 0 (0%) 2,292 (92%)
    0-1 line / invalid 4 (0.2%) 0 (0%) 0 (0%) 4 (0.2%)
    1 line / reactive 10 (0.4%) 7 (9.0%) 3 (7.1%) 0 (0%)
    2 lines / non-reactive 35 (1.3%) 25 (32%) 9 (21%) 1 (<0.1%)
    0 line / non-reactive 3 (0.1%) 0 (0%) 0 (0%) 3 (0.1%)
    0 line / DK-R 1 (<0.1%) 0 (0%) 0 (0%) 1 (<0.1%)
    1 line / DK-R 117 (4.5%) 0 (0%) 0 (0%) 117 (4.7%)
    2 lines / DK-R 29 (1.1%) 18 (23%) 9 (21%) 2 (<0.1%)
    DK-R / reactive 2 (<0.1%) 1 (1.3%) 1 (2.4%) 0 (0%)
    DK-R / DK-R 28 (1.1%) 0 (0%) 0 (0%) 28 (1.1%)
    DK-R / non-reactive 44 (1.7%) 0 (0%) 0 (0%) 44 (1.8%)
1 n (%)
2 Fisher’s exact test; Pearson’s Chi-squared test