Skip to main content

Preferences

Passport Preferences store a diner’s dietary needs, allergen restrictions, and nutritional goals. Once set, they’re applied at every participating restaurant.
Preferences UI

Reading Preferences

query GetPreferences($token: String!) {
  passport(token: $token) {
    preferences {
      diets {
        type
        displayName
      }
      allergens {
        type
        displayName
      }
      nutrients {
        type
        min
        max
      }
    }
  }
}

Example Response

{
  "data": {
    "passport": {
      "preferences": {
        "diets": [
          { "type": "Vegan", "displayName": "Vegan" }
        ],
        "allergens": [
          { "type": "Peanut", "displayName": "Peanut" },
          { "type": "Dairy", "displayName": "Dairy" }
        ],
        "nutrients": [
          { "type": "Calories", "min": null, "max": 600 },
          { "type": "Protein", "min": 20, "max": null }
        ]
      }
    }
  }
}

Updating Preferences

mutation UpdatePreferences($token: String!, $input: PreferencesInput!) {
  updatePassportPreferences(token: $token, input: $input) {
    preferences {
      diets { type }
      allergens { type }
      nutrients { type, min, max }
    }
  }
}

Input Types

input PreferencesInput {
  diets: [DietType!]
  allergens: [AllergenType!]
  nutrients: [NutrientTargetInput!]
}

input NutrientTargetInput {
  type: NutrientType!
  min: Float
  max: Float
}

Example: Set Vegan with Peanut Allergy

mutation {
  updatePassportPreferences(
    token: "user_token",
    input: {
      diets: [Vegan],
      allergens: [Peanut],
      nutrients: [
        { type: Calories, max: 600 },
        { type: Protein, min: 20 }
      ]
    }
  ) {
    preferences {
      diets { type }
    }
  }
}

Using with Menu API

Pass the Passport token to automatically apply preferences:
query {
  dishes(
    menuKey: "restaurant_key",
    passportToken: "user_passport_token"
  ) {
    results {
      dish { name }
      matchStatus  # Calculated from Passport preferences
    }
  }
}
This is equivalent to manually passing dinerPreferences:
# Without Passport - must pass preferences manually
dishes(
  menuKey: "...",
  dinerPreferences: {
    diets: [Vegan],
    excludeAllergens: [Peanut],
    calorieRange: { max: 600 }
  }
)

# With Passport - preferences loaded automatically
dishes(
  menuKey: "...",
  passportToken: "user_token"
)

Preference Types

Diets

TypeDescription
VeganNo animal products
VegetarianNo meat, may include dairy/eggs
PescatarianNo meat except fish/seafood
GlutenFreeNo gluten-containing ingredients
DairyFreeNo dairy products

Allergens

TypeDescription
DairyMilk and milk products
EggEggs and egg products
FishFish
ShellfishShrimp, crab, lobster, etc.
WheatWheat and wheat products
TreeNutAlmonds, walnuts, cashews, etc.
PeanutPeanuts and peanut products
SesameSesame seeds and sesame oil
SoySoybeans and soy products
GlutenGluten proteins

Nutrients

TypeUnitDescription
CalorieskcalTotal calories
ProteingProtein
CarbohydratesgTotal carbs
FatgTotal fat
SodiummgSodium
FibergDietary fiber
SugargTotal sugars

Building a Preferences UI

function PreferencesEditor({ token }) {
  const { data } = useQuery(GET_PREFERENCES, { variables: { token } });
  const [updatePreferences] = useMutation(UPDATE_PREFERENCES);

  const [diets, setDiets] = useState([]);
  const [allergens, setAllergens] = useState([]);
  const [calorieMax, setCalorieMax] = useState(null);

  useEffect(() => {
    if (data?.passport?.preferences) {
      setDiets(data.passport.preferences.diets.map(d => d.type));
      setAllergens(data.passport.preferences.allergens.map(a => a.type));
      // ...
    }
  }, [data]);

  const handleSave = async () => {
    await updatePreferences({
      variables: {
        token,
        input: {
          diets,
          allergens,
          nutrients: [
            { type: 'Calories', max: calorieMax }
          ]
        }
      }
    });
  };

  return (
    <div>
      <section>
        <h3>My Dietary Preferences</h3>
        <p>These preferences are applied every time I open an EveryBite menu.</p>

        <div className="diets">
          <h4>Diets</h4>
          {['Vegan', 'Vegetarian', 'Pescatarian'].map(diet => (
            <Checkbox
              key={diet}
              label={diet}
              checked={diets.includes(diet)}
              onChange={() => toggleDiet(diet)}
            />
          ))}
        </div>

        <div className="allergens">
          <h4>Allergens</h4>
          {ALLERGEN_TYPES.map(allergen => (
            <Checkbox
              key={allergen}
              label={allergen}
              checked={allergens.includes(allergen)}
              onChange={() => toggleAllergen(allergen)}
            />
          ))}
        </div>

        <div className="nutrients">
          <h4>Nutrients</h4>
          <RangeSlider
            label="Calories"
            max={2500}
            value={calorieMax}
            onChange={setCalorieMax}
          />
        </div>

        <button onClick={handleSave}>Save Preferences</button>
      </section>
    </div>
  );
}

Cross-Restaurant Application

The key value of Passport preferences:
  1. Diner sets preferences in your app (or any EveryBite app)
  2. Preferences sync to their Passport profile
  3. Any participating restaurant can access these preferences
  4. Match status calculated consistently everywhere
┌─────────────┐     ┌─────────────┐     ┌─────────────┐
│   Your App  │     │  Passport   │     │ Other Apps  │
│             │────▶│             │◀────│             │
│ Set prefs   │     │ Stores data │     │ Read prefs  │
└─────────────┘     └─────────────┘     └─────────────┘