> ## Documentation Index
> Fetch the complete documentation index at: https://docs.synapsebuilder.org/llms.txt
> Use this file to discover all available pages before exploring further.

# Shipping Customization

> Customize shipping rates and delivery options with Shopify Functions

## Overview

Shipping Customization Functions let you modify shipping rates, hide/show shipping options, rename delivery methods, and add custom shipping logic based on cart contents, location, or customer data.

## Use Cases

<CardGroup cols={2}>
  <Card title="Hide Shipping Methods" icon="eye-slash">
    Remove options based on conditions

    * Hide express for remote areas
    * Remove free shipping below threshold
    * Restrict by product type
  </Card>

  <Card title="Adjust Rates" icon="dollar-sign">
    Modify shipping costs dynamically

    * Add handling fees
    * Apply discounts
    * Bulk order pricing
    * Weight-based adjustments
  </Card>

  <Card title="Rename Methods" icon="tag">
    Customize shipping option names

    * Add delivery estimates
    * Show carrier names
    * Include pricing details
  </Card>

  <Card title="Reorder Options" icon="arrows-up-down">
    Change shipping method order

    * Promote fastest option
    * Prioritize cheapest
    * Customer preference
  </Card>
</CardGroup>

## How It Works

<Steps>
  <Step title="Checkout Loads">
    Customer enters shipping address in checkout
  </Step>

  <Step title="Rates Calculated">
    Shopify calculates available shipping rates
  </Step>

  <Step title="Function Executes">
    Your function receives cart data and shipping rates
  </Step>

  <Step title="Rates Customized">
    Function returns modified rates and options
  </Step>

  <Step title="Checkout Updates">
    Customer sees customized shipping options
  </Step>
</Steps>

## Example: Free Shipping Threshold

Generate a function that offers free shipping over \$100:

<Steps>
  <Step title="Describe Your Function">
    ```
    Create a shipping customization function that renames the 
    Standard Shipping option to show "Free Shipping" when cart 
    total is over $100, and updates the rate to $0. Below $100, 
    show normal shipping rates.
    ```
  </Step>

  <Step title="Review Generated Code">
    Synapse creates:

    * Function logic (Rust or JavaScript)
    * Input query for cart and shipping data
    * Rate modification logic
    * Configuration
  </Step>

  <Step title="Deploy & Test">
    * Automatic validation
    * Deployed to dev store
    * Test with different cart totals
  </Step>

  <Step title="Test in Checkout">
    1. Add items to cart
    2. Go to checkout
    3. Enter shipping address
    4. See customized shipping options
  </Step>
</Steps>

## Generated Function Structure

```
extensions/shipping-customization/
├── src/
│   ├── run.rs                 # Function logic (Rust)
│   │   OR
│   ├── run.js                 # Function logic (JS)
│   └── run.graphql           # Input query
├── shopify.extension.toml     # Config
└── Cargo.toml / package.json
```

## Function Code Examples

<Tabs>
  <Tab title="Free Shipping Threshold (Rust)">
    ```rust theme={null}
    use shopify_function::prelude::*;
    use shopify_function::Result;
    use rust_decimal::Decimal;

    #[shopify_function_target(
        query_path = "src/run.graphql",
        schema_path = "schema.graphql"
    )]
    fn run(input: input::ResponseData) -> Result<output::FunctionRunResult> {
        // Calculate cart total
        let cart_total = Decimal::from_str(
            &input.cart.cost.subtotal_amount.amount
        ).unwrap_or(Decimal::ZERO);
        
        let threshold = Decimal::from(100);
        
        let operations = input
            .cart
            .delivery_groups
            .iter()
            .flat_map(|group| {
                group.delivery_options.iter().filter_map(|option| {
                    // Check if this is standard shipping
                    if option.title.to_lowercase().contains("standard") {
                        if cart_total >= threshold {
                            // Free shipping!
                            return Some(output::Operation::Update(
                                output::UpdateOperation {
                                    delivery_option_handle: option.handle.clone(),
                                    title: Some("Free Standard Shipping".to_string()),
                                    price: Some(Decimal::ZERO),
                                }
                            ));
                        }
                    }
                    None
                })
            })
            .collect();
        
        Ok(output::FunctionRunResult { operations })
    }
    ```
  </Tab>

  <Tab title="Hide Express for Remote Areas (JavaScript)">
    ```javascript theme={null}
    export function run(input) {
      const address = input.cart.deliveryGroups[0]?.deliveryAddress;
      const remoteZipCodes = ['99999', '88888', '77777'];
      
      const isRemote = remoteZipCodes.includes(address?.zip);
      
      const operations = [];
      
      if (isRemote) {
        input.cart.deliveryGroups.forEach(group => {
          group.deliveryOptions.forEach(option => {
            if (option.title.includes('Express')) {
              operations.push({
                hide: {
                  deliveryOptionHandle: option.handle
                }
              });
            }
          });
        });
      }
      
      return { operations };
    }
    ```
  </Tab>

  <Tab title="Add Handling Fee">
    ```rust theme={null}
    // Add $5 handling fee for fragile items
    let has_fragile = input.cart.lines.iter()
        .any(|line| line.merchandise.product.has_tags(vec!["fragile"]));

    if has_fragile {
        let operations = input.cart.delivery_groups
            .iter()
            .flat_map(|group| {
                group.delivery_options.iter().map(|option| {
                    let current_price = Decimal::from_str(&option.cost.amount)
                        .unwrap_or(Decimal::ZERO);
                    let new_price = current_price + Decimal::from(5);
                    
                    output::Operation::Update(output::UpdateOperation {
                        delivery_option_handle: option.handle.clone(),
                        title: Some(format!("{} (+ fragile handling)", option.title)),
                        price: Some(new_price),
                    })
                })
            })
            .collect();
    }
    ```
  </Tab>

  <Tab title="Input Query">
    ```graphql theme={null}
    query RunInput {
      cart {
        cost {
          subtotalAmount {
            amount
          }
        }
        lines {
          merchandise {
            ... on ProductVariant {
              product {
                hasTags(tags: ["fragile", "heavy", "oversized"])
              }
            }
          }
        }
        deliveryGroups {
          deliveryAddress {
            countryCode
            provinceCode
            zip
          }
          deliveryOptions {
            handle
            title
            description
            cost {
              amount
            }
          }
        }
      }
    }
    ```
  </Tab>
</Tabs>

## Common Patterns

<AccordionGroup>
  <Accordion title="Cart Value Shipping Tiers" icon="layer-group">
    Different shipping costs at different cart values:

    ```rust theme={null}
    let cart_total = parse_amount(&input.cart.cost.subtotal_amount.amount);

    let shipping_discount = if cart_total >= 100.0 {
        1.0  // Free (100% discount)
    } else if cart_total >= 75.0 {
        0.5  // 50% off
    } else if cart_total >= 50.0 {
        0.25 // 25% off
    } else {
        0.0  // No discount
    };

    let operations = input.cart.delivery_groups
        .iter()
        .flat_map(|group| {
            group.delivery_options.iter().map(|option| {
                let current_price = parse_amount(&option.cost.amount);
                let new_price = current_price * (1.0 - shipping_discount);
                
                Operation::Update(UpdateOperation {
                    delivery_option_handle: option.handle.clone(),
                    price: Some(Decimal::from_f64(new_price).unwrap()),
                    title: if shipping_discount == 1.0 {
                        Some(format!("Free {}", option.title))
                    } else {
                        None
                    },
                })
            })
        })
        .collect();
    ```

    **Prompt Example:**

    ```
    "Create tiered shipping discounts: Free shipping over $100, 
    50% off shipping for $75-$99, 25% off for $50-$74, normal 
    rates below $50. Update titles to show 'Free' when applicable."
    ```
  </Accordion>

  <Accordion title="Product-Based Restrictions" icon="box">
    Hide shipping options based on cart contents:

    ```rust theme={null}
    let has_oversized = input.cart.lines.iter()
        .any(|line| line.merchandise.product.has_tags(vec!["oversized"]));

    if has_oversized {
        // Only allow freight shipping for oversized items
        let operations = input.cart.delivery_groups
            .iter()
            .flat_map(|group| {
                group.delivery_options.iter().filter_map(|option| {
                    if !option.title.to_lowercase().contains("freight") {
                        Some(Operation::Hide(HideOperation {
                            delivery_option_handle: option.handle.clone(),
                        }))
                    } else {
                        None
                    }
                })
            })
            .collect();
    }
    ```

    **Prompt Example:**

    ```
    "If cart contains products tagged 'oversized', hide all shipping 
    methods except Freight Shipping. Show a message that oversized 
    items require freight delivery."
    ```
  </Accordion>

  <Accordion title="Location-Based Pricing" icon="location-dot">
    Adjust shipping rates by destination:

    ```rust theme={null}
    let country = input.cart.delivery_groups[0]
        .delivery_address
        .country_code
        .as_str();

    let surcharge = match country {
        "AU" => 15.0,  // Australia surcharge
        "NZ" => 12.0,  // New Zealand surcharge
        "JP" => 20.0,  // Japan surcharge
        _ => 0.0,
    };

    if surcharge > 0.0 {
        let operations = input.cart.delivery_groups
            .iter()
            .flat_map(|group| {
                group.delivery_options.iter().map(|option| {
                    let current_price = parse_amount(&option.cost.amount);
                    let new_price = current_price + surcharge;
                    
                    Operation::Update(UpdateOperation {
                        delivery_option_handle: option.handle.clone(),
                        price: Some(Decimal::from_f64(new_price).unwrap()),
                    })
                })
            })
            .collect();
    }
    ```

    **Prompt Example:**

    ```
    "Add $15 surcharge to all shipping methods for Australian 
    customers, $12 for New Zealand, $20 for Japan. Keep other 
    countries at normal rates."
    ```
  </Accordion>

  <Accordion title="Add Delivery Estimates" icon="calendar">
    Show estimated delivery dates in shipping option names:

    ```rust theme={null}
    use chrono::{Utc, Duration};

    let operations = input.cart.delivery_groups
        .iter()
        .flat_map(|group| {
            group.delivery_options.iter().map(|option| {
                let days = if option.title.contains("Express") {
                    1
                } else if option.title.contains("Standard") {
                    5
                } else {
                    7
                };
                
                let delivery_date = Utc::now() + Duration::days(days);
                let formatted = delivery_date.format("%b %d");
                
                Operation::Update(UpdateOperation {
                    delivery_option_handle: option.handle.clone(),
                    title: Some(format!(
                        "{} (Arrives by {})",
                        option.title,
                        formatted
                    )),
                    price: None,
                })
            })
        })
        .collect();
    ```

    **Prompt Example:**

    ```
    "Add estimated delivery dates to shipping method names. Express 
    delivers in 1 day, Standard in 5 days, Economy in 7 days. 
    Format as 'Method Name (Arrives by Nov 5)'"
    ```
  </Accordion>
</AccordionGroup>

## Operation Types

Shipping functions support these operations:

<Tabs>
  <Tab title="Update">
    Modify shipping rate or name:

    ```rust theme={null}
    Operation::Update(UpdateOperation {
        delivery_option_handle: option.handle.clone(),
        title: Some("Free Shipping".to_string()),
        price: Some(Decimal::ZERO),
    })
    ```

    * Change rate amount
    * Update display name
    * Modify description
  </Tab>

  <Tab title="Hide">
    Remove shipping option:

    ```rust theme={null}
    Operation::Hide(HideOperation {
        delivery_option_handle: option.handle.clone(),
    })
    ```

    * Not available for cart
    * Restricted by location
    * Product incompatibility
  </Tab>

  <Tab title="Move">
    Reorder shipping options:

    ```rust theme={null}
    Operation::Move(MoveOperation {
        delivery_option_handle: option.handle.clone(),
        index: 0, // Move to top
    })
    ```

    * Promote preferred method
    * Prioritize fastest/cheapest
    * Custom ordering logic
  </Tab>
</Tabs>

## Advanced Examples

<AccordionGroup>
  <Accordion title="Weight-Based Pricing">
    ```rust theme={null}
    let total_weight: f64 = input.cart.lines.iter()
        .map(|line| {
            let weight = line.merchandise.weight
                .as_ref()
                .and_then(|w| w.value.parse::<f64>().ok())
                .unwrap_or(0.0);
            weight * line.quantity as f64
        })
        .sum();

    // Add $2 per kg over 5kg
    let weight_surcharge = if total_weight > 5.0 {
        (total_weight - 5.0) * 2.0
    } else {
        0.0
    };

    let operations = input.cart.delivery_groups
        .iter()
        .flat_map(|group| {
            group.delivery_options.iter().map(|option| {
                let current_price = parse_amount(&option.cost.amount);
                let new_price = current_price + weight_surcharge;
                
                Operation::Update(UpdateOperation {
                    delivery_option_handle: option.handle.clone(),
                    price: Some(Decimal::from_f64(new_price).unwrap()),
                    title: if weight_surcharge > 0.0 {
                        Some(format!(
                            "{} (+ ${:.2} heavy item fee)",
                            option.title,
                            weight_surcharge
                        ))
                    } else {
                        None
                    },
                })
            })
        })
        .collect();
    ```
  </Accordion>

  <Accordion title="Customer Tier Shipping">
    ```rust theme={null}
    let customer_tier = input.cart.buyer_identity
        .as_ref()
        .and_then(|id| id.customer.as_ref())
        .and_then(|c| {
            if c.has_tags(vec!["vip"]) { Some("VIP") }
            else if c.has_tags(vec!["premium"]) { Some("Premium") }
            else { None }
        });

    let discount = match customer_tier {
        Some("VIP") => 1.0,      // Free shipping
        Some("Premium") => 0.5,  // 50% off
        _ => 0.0,
    };

    let operations = input.cart.delivery_groups
        .iter()
        .flat_map(|group| {
            group.delivery_options.iter().map(|option| {
                let current_price = parse_amount(&option.cost.amount);
                let new_price = current_price * (1.0 - discount);
                
                Operation::Update(UpdateOperation {
                    delivery_option_handle: option.handle.clone(),
                    price: Some(Decimal::from_f64(new_price).unwrap()),
                    title: if discount == 1.0 {
                        Some(format!("Free {} (VIP)", option.title))
                    } else if discount > 0.0 {
                        Some(format!("{} ({}% off)", option.title, (discount * 100.0) as i32))
                    } else {
                        None
                    },
                })
            })
        })
        .collect();
    ```
  </Accordion>

  <Accordion title="Bulk Order Shipping">
    ```rust theme={null}
    let total_quantity: i64 = input.cart.lines.iter()
        .map(|line| line.quantity)
        .sum();

    // Free shipping for bulk orders (20+ items)
    if total_quantity >= 20 {
        let operations = input.cart.delivery_groups
            .iter()
            .flat_map(|group| {
                group.delivery_options.iter().map(|option| {
                    Operation::Update(UpdateOperation {
                        delivery_option_handle: option.handle.clone(),
                        title: Some(format!("Free {} (Bulk Order)", option.title)),
                        price: Some(Decimal::ZERO),
                    })
                })
            })
            .collect();
    }
    ```
  </Accordion>
</AccordionGroup>

## Testing Shipping Functions

<Steps>
  <Step title="Test in Checkout">
    1. Add items to cart
    2. Go to checkout
    3. Enter various shipping addresses
    4. Verify rates update correctly
  </Step>

  <Step title="Test Different Scenarios">
    * Various cart values
    * Different product combinations
    * Multiple shipping addresses
    * International vs domestic
  </Step>

  <Step title="Check Function Logs">
    ```bash theme={null}
    shopify app function logs --watch
    ```

    Monitor function executions
  </Step>

  <Step title="Performance Testing">
    * Should execute in under 5ms
    * Test with many shipping options
    * Large cart edge cases
  </Step>
</Steps>

## Best Practices

<CardGroup cols={2}>
  <Card title="Always Show Options" icon="exclamation-triangle">
    Never hide all shipping methods

    Ensure at least one method remains visible
  </Card>

  <Card title="Clear Messaging" icon="text">
    Explain rate changes

    Show why fees added or discounts applied
  </Card>

  <Card title="Handle Errors" icon="shield">
    Graceful fallbacks

    Return empty operations on errors, don't crash
  </Card>

  <Card title="Performance" icon="gauge">
    Keep functions fast

    Minimize loops, use Rust, cache calculations
  </Card>
</CardGroup>

## Example Prompts

<AccordionGroup>
  <Accordion title="Progressive Free Shipping">
    ```
    Create a shipping function with tiers: free shipping over $100, 
    50% off shipping for $50-$99, normal rates below $50. Update 
    the shipping method names to show the discount percentage.
    ```
  </Accordion>

  <Accordion title="Fragile Item Handling Fee">
    ```
    If cart contains any products tagged 'fragile', add a $5 
    handling fee to all shipping methods and update the name to 
    show '(+ fragile handling fee)'.
    ```
  </Accordion>

  <Accordion title="Express for VIP Only">
    ```
    Hide Express Shipping for regular customers. Only show Express 
    to customers tagged 'vip'. Keep Standard and Economy visible 
    for everyone.
    ```
  </Accordion>

  <Accordion title="Remote Area Surcharge">
    ```
    For zip codes in remote areas (list: 99999, 88888, 77777), 
    add $10 to all shipping methods and update name to show 
    '(+ remote area surcharge)'.
    ```
  </Accordion>
</AccordionGroup>

## Troubleshooting

<AccordionGroup>
  <Accordion title="No Shipping Options">
    **Cause:** Function hiding all methods

    **Solution:** Add safeguard to keep at least one visible
  </Accordion>

  <Accordion title="Rates Not Updating">
    **Cause:** Price calculation error

    **Solution:** Check Decimal parsing, handle errors with unwrap\_or
  </Accordion>

  <Accordion title="Function Not Running">
    **Cause:** Deployment issue

    **Solution:** Check deployment logs, verify function active
  </Accordion>
</AccordionGroup>

## Next Steps

<CardGroup cols={2}>
  <Card title="Discount Functions" icon="percent" href="/guides/discount-functions">
    Create custom discount logic
  </Card>

  <Card title="Payment Customization" icon="credit-card" href="/guides/payment-customization">
    Customize payment methods
  </Card>

  <Card title="Functions Overview" icon="function" href="/essentials/functions">
    Learn about all function types
  </Card>

  <Card title="Debugging" icon="bug" href="/advanced/debugging">
    Debug and optimize functions
  </Card>
</CardGroup>
