Find a Member Across BNI Chapters

Site bniconnectglobal.comTask find-cross-chapter-memberVersion v4Updated Aug 4, 2026Category browser-automation

Open BNI Connect Global's authenticated referral form, inspect its fields, and use its cross-chapter lookup to find a member by name. This skill was captured from a live agent session on bniconnectglobal.com and publishes here verbatim, exactly as an agent receives it.

NoteSelectors and URL schemes drift as sites change. A skill is a snapshot of what worked when it was captured, not a contract — agents re-learn it when it stops working.

Purpose

Open the authenticated BNI Connect Global referral form, inspect its controls, and use 跨分會查找 to search for {member-name} across chapters. Return the rendered referral-form fields and matching member results. Credentials and transient session identifiers are runtime-only.

When to Use

Use when a caller needs to inspect or fill an internal referral form, or locate a BNI member in another chapter from that form. This is a lookup and inspection workflow; do not select a member or submit a referral unless separately requested and confirmed.

Workflow

  1. If authentication is required, navigate to https://www.bniconnectglobal.com/login, fill input[name="username"] and input[name="password"] with runtime credentials, activate button[type="submit"], and wait for the authenticated /web/ portal. Never retain credentials or expose the transient ;jsessionid.
  2. On the authenticated dashboard, run the referral-form opener below. Activate only the visible exact 提交 control whose nearby container contains 提供引薦, excluding containers containing 交易金額, 一對一, 分會教育, or equivalent unrelated forms. No stable direct referral-form URL was observed.
  3. Wait for the referral form dialog or rendered form, then run the referral-form field inspector below. It returns visible selects, inputs, textareas, radio buttons, checkboxes, labels, values, and nearby form context without changing data.
  4. If cross-chapter lookup is needed, run the cross-chapter opener below. Match normalized visible text 跨分會查找; do not rely on generated Material UI classes or DOM indexes.
  5. Wait for the cross-chapter UI. If it contains a search area labeled 要搜尋其他使用者 with two text inputs, populate the fields by local labels/context rather than global indexes. The observed installation accepted the family-name component in the first field and the given-name component in the second; a partial search such as {family-name} in the first field with an empty {given-name} can be used when appropriate. Activate the localized exact 查找 control.
  6. If instead a single search field is present, identify it by label, placeholder, name, or nearby context matching member/name/search terminology, set {member-name}, then activate the qualified 查找/search control.
  7. Wait for result rows or a no-results message and run the result extractor below on the current page. Return all distinct rows containing {member-name}, including complete visible text, chapter/member metadata, links, and buttons. Do not select or submit a result unless explicitly requested.

Referral-form opener:

(() => {
  const v = (e) =>
      !!e && (e.offsetWidth || e.offsetHeight || e.getClientRects().length),
    c = (s) => (s || "").replace(/\s+/g, " ").trim(),
    yes = /提供引薦|provide referral|referral/i,
    no = /交易金額|submit tyfcb|一對一|一对一|one[- ]to[- ]one|1-2-1|分會教育/i,
    els = [...document.querySelectorAll('button,[role="button"],a,div,span')]
      .filter(v)
      .filter(
        (e) =>
          c(e.innerText || e.textContent) === "提交" &&
          ![...e.children].some((x) => c(x.innerText || x.textContent) === "提交"),
      );
  for (const e of els) {
    let p = e;
    for (let i = 0; i < 8 && p; i++, p = p.parentElement) {
      const t = c(p.innerText || p.textContent);
      if (yes.test(t) && !no.test(t) && t.length < 500) {
        e.click();
        return { opened: true, label: "提交", context: t };
      }
    }
  }
  return {
    opened: false,
    reason: "context-qualified referral submit control not found",
  };
})();

Referral-form field inspector:

(() => {
  const v = (e) =>
      !!e && (e.offsetWidth || e.offsetHeight || e.getClientRects().length),
    c = (s) => (s || "").replace(/\s+/g, " ").trim(),
    r = document.querySelector('div[role="dialog"]') || document,
    ctx = (e) =>
      c(
        e.closest(".MuiFormControl-root,.MuiFormControl,fieldset,form,div")
          ?.innerText || "",
      ).slice(0, 500),
    label = (e) =>
      c(
        e.getAttribute("aria-label") ||
          e.getAttribute("placeholder") ||
          e.getAttribute("name") ||
          ctx(e),
      ),
    value = (e) => c(e.value ?? e.innerText ?? e.textContent),
    fields = [
      ...r.querySelectorAll(
        'input,textarea,select,[role="combobox"],.MuiSelect-select',
      ),
    ]
      .filter(v)
      .map((e, i) => ({
        index: i,
        tag: e.tagName.toLowerCase(),
        type: e.getAttribute("type"),
        id: e.id || null,
        name: e.getAttribute("name"),
        label: label(e),
        value: value(e),
        checked: e.checked === true,
        readOnly: e.readOnly === true,
        disabled: e.disabled === true,
        context: ctx(e),
      })),
    buttons = [...r.querySelectorAll('button,[role="button"],input[type="submit"]')]
      .filter(v)
      .map((e, i) => ({
        index: i,
        label: c(
          e.innerText || e.textContent || e.value || e.getAttribute("aria-label"),
        ),
        disabled: !!e.disabled,
      }));
  return {
    url: location.href,
    dialog: !!document.querySelector('div[role="dialog"]'),
    title: c(r.querySelector('h1,h2,h3,[role="heading"]')?.innerText),
    fieldCount: fields.length,
    fields,
    buttons,
    formText: c(r.innerText || r.textContent).slice(0, 5000),
  };
})();

Cross-chapter opener:

(() => {
  const v = (e) =>
      !!e && (e.offsetWidth || e.offsetHeight || e.getClientRects().length),
    c = (s) => (s || "").replace(/\s+/g, " ").trim(),
    root = document.querySelector('div[role="dialog"]') || document,
    els = [...root.querySelectorAll('button,[role="button"],a,div,span')]
      .filter(v)
      .filter(
        (e) =>
          c(e.innerText || e.textContent) === "跨分會查找" &&
          ![...e.children].some(
            (x) => c(x.innerText || x.textContent) === "跨分會查找",
          ),
      );
  if (!els.length)
    return { opened: false, reason: "cross-chapter lookup control not found" };
  els[0].click();
  return { opened: true, label: "跨分會查找" };
})();

Two-part search helper:

((familyName = "", givenName = "") => {
  const v = (e) =>
      !!e && (e.offsetWidth || e.offsetHeight || e.getClientRects().length),
    c = (s) => (s || "").replace(/\s+/g, " ").trim(),
    root = document.querySelector('div[role="dialog"]') || document,
    box =
      [...root.querySelectorAll("div")]
        .filter(v)
        .find(
          (e) =>
            /要搜尋其他使用者/i.test(c(e.innerText || e.textContent)) &&
            c(e.innerText || e.textContent).length < 500,
        ) || root,
    fields = [
      ...box.querySelectorAll('input[type="text"],input:not([type])'),
    ].filter(v),
    set = (e, val) => {
      const p = Object.getOwnPropertyDescriptor(
        Object.getPrototypeOf(e),
        "value",
      )?.set;
      if (p) p.call(e, val);
      else e.value = val;
      e.dispatchEvent(new Event("input", { bubbles: true }));
      e.dispatchEvent(new Event("change", { bubbles: true }));
    };
  if (fields.length < 2)
    return {
      searched: false,
      reason: "two-part search fields not found",
      fieldCount: fields.length,
    };
  set(fields[0], familyName);
  set(fields[1], givenName);
  const b = [...box.querySelectorAll('button,[role="button"],a,div,span')]
    .filter(v)
    .find(
      (e) =>
        c(e.innerText || e.textContent) === "查找" &&
        ![...e.children].some((x) => c(x.innerText || x.textContent) === "查找"),
    );
  if (!b)
    return {
      searched: false,
      reason: "查找 control not found",
      fieldCount: fields.length,
    };
  b.click();
  return {
    searched: true,
    fieldCount: fields.length,
    fields: fields.map((e) => ({
      name: e.getAttribute("name"),
      id: e.id || null,
      value: e.value,
    })),
    button: "查找",
  };
})("{family-name}", "{given-name}");

Single-field search inspector/setter:

((query = "") => {
  const v = (e) =>
      !!e && (e.offsetWidth || e.offsetHeight || e.getClientRects().length),
    c = (s) => (s || "").replace(/\s+/g, " ").trim(),
    r = document.querySelector('div[role="dialog"]') || document,
    ctx = (e) =>
      c(
        e.closest("fieldset,.MuiFormControl-root,.MuiFormControl,form,div")
          ?.innerText || "",
      ),
    field = [
      ...r.querySelectorAll(
        'input[type="text"],input:not([type]),input[type="search"],textarea',
      ),
    ]
      .filter(v)
      .find((e) =>
        /姓名|會員|成員|查找|搜尋|搜索|name|member|search/i.test(
          [
            e.getAttribute("aria-label"),
            e.getAttribute("placeholder"),
            e.getAttribute("name"),
            ctx(e),
          ]
            .filter(Boolean)
            .join(" "),
        ),
      ),
    set =
      field &&
      Object.getOwnPropertyDescriptor(Object.getPrototypeOf(field), "value")?.set;
  if (field && query !== "") {
    if (set) set.call(field, query);
    else field.value = query;
    field.dispatchEvent(new Event("input", { bubbles: true }));
    field.dispatchEvent(new Event("change", { bubbles: true }));
  }
  const buttons = [
      ...r.querySelectorAll('button,[role="button"],input[type="submit"]'),
    ].filter(v),
    search = buttons.find(
      (e) =>
        /查找|搜尋|搜索|搜尋會員|search/i.test(
          c(e.innerText || e.textContent || e.value || e.getAttribute("aria-label")),
        ) && !e.disabled,
    );
  return {
    query,
    selectedField: field
      ? { name: field.getAttribute("name"), id: field.id || null }
      : null,
    searchCandidate: search
      ? { label: c(search.innerText || search.textContent || search.value) }
      : null,
    instructions:
      field && search
        ? "activate the returned search button and wait for results"
        : "inspect fields and qualify the localized search control",
  };
})("{member-name}");

Cross-chapter result extractor:

((memberName = "") => {
  const v = (e) =>
      !!e && (e.offsetWidth || e.offsetHeight || e.getClientRects().length),
    c = (s) => (s || "").replace(/\s+/g, " ").trim(),
    q = c(memberName).toLocaleLowerCase(),
    root = document.querySelector('div[role="dialog"]') || document,
    selectors = [
      "table tbody tr",
      "table tr",
      '[role="row"]',
      ".MuiDataGrid-row",
      "li",
      ".card",
      '[class*="card"]',
      '[class*="list-item"]',
    ],
    seen = new Set(),
    rows = [];
  for (const sel of selectors)
    for (const el of root.querySelectorAll(sel)) {
      if (!v(el) || seen.has(el)) continue;
      seen.add(el);
      const text = c(el.innerText || el.textContent);
      if (!text || (q && !text.toLocaleLowerCase().includes(q))) continue;
      const links = [...el.querySelectorAll("a")].filter(v).map((a) => ({
          text: c(a.innerText || a.textContent),
          href: a.href,
          title: c(a.title),
          ariaLabel: c(a.getAttribute("aria-label")),
        })),
        buttons = [...el.querySelectorAll('button,[role="button"]')]
          .filter(v)
          .map((b) => ({
            text: c(b.innerText || b.textContent),
            title: c(b.title),
            ariaLabel: c(b.getAttribute("aria-label")),
          }));
      rows.push({
        text,
        memberMatch: q ? text.toLocaleLowerCase().includes(q) : true,
        links,
        buttons,
        tag: el.tagName.toLowerCase(),
        className: typeof el.className === "string" ? el.className : "",
      });
    }
  const matches = rows.filter(
    (x, i) => !rows.some((y, j) => i !== j && y.text === x.text),
  );
  return {
    query: memberName,
    matchCount: matches.length,
    matches,
    noResults:
      matches.length === 0 &&
      /無資料|查無|沒有結果|no results|not found/i.test(
        c(root.innerText || root.textContent),
      ),
  };
})("{member-name}");

Site-Specific Gotchas

  • The referral form is opened from the dashboard through a context-qualified 提交 control associated with 提供引薦; do not click an arbitrary 提交 button.
  • The observed installation exposed no stable direct URL for the referral form or cross-chapter lookup.
  • 跨分會查找 is an exact localized control inside the referral form; generated Material UI classes and element types may vary.
  • The lookup may show two inputs under 要搜尋其他使用者. In the observed run, putting a partial member-name component in the first field and leaving the second blank successfully initiated the lookup; do not assume both fields must be nonempty.
  • The referral form itself contains a mixture of Material UI selects, regular inputs, textareas, radio buttons, and checkboxes. Use the field inspector to identify labels, names, values, disabled/read-only state, and nearby context before filling; do not rely on global indexes.
  • The observed result area used a table with 名稱 and 分會 columns. Prefer complete table-row text and row-scoped links/controls; the generic extractor also supports Material UI rows, lists, and cards.
  • Search-field and result markup may vary. Qualify fields and search buttons by visible labels, placeholders, and nearby form context; inspect before acting if no candidate is found.
  • The cross-chapter UI may be a dialog or embedded section. Wait for its rendered fields/results before extraction.
  • Result containers may be nested; deduplicate by complete visible text.
  • Do not infer opaque member IDs or construct member URLs. Use only observed result links and metadata.
  • Authentication may redirect to /web/ with a transient ;jsessionid=...; preserve the session but never hard-code or expose it.
  • Keep usernames, passwords, cookies, and session URLs runtime-only.

Expected Output

Return whether the referral form and 跨分會查找 lookup opened, the authenticated route without exposing session identifiers, the referral-form field inspector output, identified search field(s) and search control, and matchCount with every matching member row's complete visible text, chapter/member context, observed links, buttons, and no-results state. Do not claim a referral was filled or submitted unless explicitly requested and separately verified.

Call it

GET https://production-sfo.browserless.io/skills?token=TOKEN-HERE&domain=bniconnectglobal.com&task=find-cross-chapter-member