Limit per IP address & users unable to add products in cart
Unfortunately, in the last week Shopify’s support team wasn’t helpful with problems we are experiencing on our webshop so I’m wondering if anyone had similar issues. Our website is running on two platforms: Shopify + CMS platform we use for landing pages, home page etc.
10 days ago we noticed that some users are experiencing problems with ‘add to cart’ button - if they try to add a product, their Shopify cart in a slider is blank and contains no products. If they would click on the checkout button, Shopify’s page would show error message: too many attempts
After several days and 2 completely misleading answers by Shopify, our developers realised that the problem is as follows:
- Shopify has a server limit of x changes of the cart within x minutes, per customer
- That way Shopify probably wants to prevent attacks where somebody would change its cart a lot of times in order to slow down Shopify's servers as that action consumes processing power
- Since we have a proxy server, which is between the customer and the Shopify server, all cart changes done by all visitors together count as if they were done by one single customer (one IP address) which very fast hits the cart changes limit of Shopify --> and users cannot add products to a cart
Shopify confirmed that afterwards:
I looked through the logs and over all of the information your provided. You are hitting our cart creation throttle because the same IP address is shown as creating more than our allowed amount of carts for one IP address per hour. Currently, this is not something that we can change nor can we whitelist your IP for but a different set up will be needed.
Shopify refused to increase that limit or whitelist an IP address of our proxy server. They suggested that a different set up is needed but didn’t specify that in concrete. I am sure that we are not the first shop that combines 2 platforms or uses a proxy server.
Has anyone experience in that area? How do you solve a limit per one IP address?
We even suggested to put the whole checkout process in an iframe - asked for Shopify’s advice but after 4 days, still no answer.
As Shopify Plus users, we are really disapointed in their support and how slow they are responding. In the meantime, we did a temporary workaround but some users still have the same problem and cannot add products in a cart. We are losing customers and our conversion rate is in a decrease but seems like we’ll have to figure this out on our own :/
Thank you in advance for any suggestion!
JS async / await vs callback
Can I use async + await to make sure for example three function call finished in order ? It seem not work as intended? Because of despite the order of execution preserved, the finished time of 3 function call is not predicted, so the result will returned randomly ?
This mean JS will fire all 3 function call (in order) without wait for its results returned first ?
It sound legit since performance and/or efficiency but lead to synchronous issue ?
Javascript hoisting
"Hoisting is a JavaScript mechanism where variables and function declarations are moved to the top of their scope before code execution."
From callbacks to asnyc/await
Slate as a rescue for multiple Dev on a Liquid theme store.
Not full feature but at least we can develop some of the liquid locally.
[not related]
[view performance sql]
JS global variable
Somehow related to Application Controller or Front Controller Pattern.
This shit is not Shopify.
JS var let const in more deep shit.
Theme.liquid setting data
<script>
var theme = {
breakpoints: {
medium: 750,
large: 990,
widescreen: 1400
},
strings: {
addToCart: {{ 'products.product.add_to_cart' | t | json }},
soldOut: {{ 'products.product.sold_out' | t | json }},
unavailable: {{ 'products.product.unavailable' | t | json }},
regularPrice: {{ 'products.product.regular_price' | t | json }},
salePrice: {{ 'products.product.sale_price' | t | json }},
sale: {{ 'products.product.on_sale' | t | json }},
fromLowestPrice: {{ 'products.product.from_lowest_price_html' | t: lowest_price: '[price]' | json }},
vendor: {{'products.product.vendor' | t | json }},
showMore: {{ 'general.filters.show_more' | t | json }},
showLess: {{ 'general.filters.show_less' | t | json }},
searchFor: {{ 'general.search.search_for' | t | json }},
addressError: {{ 'sections.map.address_error' | t | json }},
addressNoResults: {{ 'sections.map.address_no_results' | t | json }},
addressQueryLimit: {{ 'sections.map.address_query_limit_html' | t | json }},
authError: {{ 'sections.map.auth_error_html' | t | json }},
newWindow: {{ 'general.accessibility.link_messages.new_window' | t | json }},
external: {{ 'general.accessibility.link_messages.external' | t | json }},
newWindowExternal: {{ 'general.accessibility.link_messages.new_window_and_external' | t | json }},
removeLabel: {{ 'cart.label.remove' | t: product: '[product]' | json }},
update: {{ 'cart.label.update' | t | json }},
quantity: {{ 'cart.label.quantity' | t | json }},
discountedTotal: {{ 'cart.label.discounted_total' | t | json }},
regularTotal: {{ 'cart.label.regular_total' | t | json }},
priceColumn: {{ 'cart.label.price_column' | t | json }},
quantityMinimumMessage: {{ 'products.product.quantity_minimum_message' | t | json }},
cartError: {{ 'cart.general.cart_error' | t | json }},
removedItemMessage: {{ 'cart.general.removed_item_html' | t: quantity: '[quantity]', link: '[link]' | json }},
unitPrice: {{ 'products.product.unit_price_label' | t | json }},
unitPriceSeparator: {{ 'general.accessibility.unit_price_separator' | t | json }},
oneCartCount: {{ 'cart.popup.cart_count' | t: count: 1 | json }},
otherCartCount: {{ 'cart.popup.cart_count' | t: count: '[count]' | json }},
quantityLabel: {{ 'cart.popup.quantity_label' | t: quantity_count: '[count]' | json }},
products: {{ 'general.search.products' | t | json }},
loading: {{ 'general.search.loading' | t | json }},
number_of_results: {{ 'general.search.number_of_results' | t: result_number: '[result_number]', results_count: '[results_count]' | json }},
number_of_results_found: {{ 'general.search.number_of_results_found' | t: results_count: '[results_count]' | json }},
one_result_found: {{ 'general.search.one_result_found' | t | json }}
},
moneyFormat: {{ shop.money_format | json }},
moneyFormatWithCurrency: {{ shop.money_with_currency_format | json }},
settings: {
predictiveSearchEnabled: {{ settings.predictive_search_enabled | json }},
predictiveSearchShowPrice: {{ settings.predictive_search_show_price | json }},
predictiveSearchShowVendor: {{ settings.predictive_search_show_vendor | json }}
}
}
document.documentElement.className = document.documentElement.className.replace('no-js', 'js');
</script>
Cool lowercase font
Automate Shopify with bash CLI
DELETE products or collections by bash commandline.
Sometime raise error like to be rate limit.
>520 Origin Error</h1></center>
<hr><center>cloudflare-nginx</center>
Eg: Bash delete custom_collections
#!/bin/bash
# Delete query
# read data file each line
input="collect.del"
while IFS= read -r line
do
# build command delete
echo "Delete ${line} \n"
#echo "curl -X DELETE https://yourshop.myshopify.com/admin/api/2020-04/products/${line}.json -H 'authorization: Basic Og==' -H 'cache-control: no-cache' -H 'postman-token: 0xxxxxxxxxx-500b-d6bd-a2736439648d' -H 'x-shopify-access-token: shpca_3xxxce7f8b914xxxxxxxxxxxx'"
curl -X DELETE https://yourshop.myshopify.com/admin/api/2020-04/custom_collections/"${line}".json -H 'authorization: Basic Og==' -H 'cache-control: no-cache' -H 'postman-token: xxxxxxxxxx-500b-d6bd-a2736439648d' -H 'x-shopify-access-token: shpca_3xxxxxxxxxxxxb838a3747657'
sleep 0.2
done < "$input"
# sleep a bit to avoid rate limit ?
# awk '{ print $6 }' delete.8k.shopi => cut column #6 in log data.
Using vue.js as Store and connect with Shopify over JS library API.
Eg. Commaai shop:
This site seem using nuxt.js and vue.js and connect with Shopify.
There are very rare example and source code for using Vue.js with Shopify, but I think It is not hard to build. The challenge is that without good opensource / guide I often lead to bad design and coding or it require much more time to refactoring etc.
Metafields
/admin/collections/#{id}/metafields.jso
POST /admin/api/2020-04/metafields.json
{
"metafield": {
"namespace": "inventory",
"key": "warehouse",
"value": 25,
"value_type": "integer"
}
}
Line ab 300
/**
* createCollectionMetafield() method
*
* reference: https://help.shopify.com/api/reference/metafield
*/
"createCollectionMetafield" => array(
"httpMethod" => "POST",
"uri" => "/admin/collections/{id}/metafields.json",
"summary" => "Create a new metafield for a collection",
"responseModel" => "defaultJsonResponse",
"parameters" => array(
"id" => array(
"type" => "number",
"location" => "uri",
"description" => "The ID of the Collection.",
"required" => true
),
"metafield" => array(
"location" => "json",
"parameters" => array(
"namespace" => array(
"type" => "string",
"location" => "json",
"description" => "The Namespace for the Metafield."
),
"key" => array(
"type" => "string",
"location" => "json",
"description" => "The Key for the Metafield."
),
"value" => array(
"type" => "string",
"location" => "json",
"description" => "The Value of the Metafield."
),
"value_type" => array(
"type" => "string",
"location" => "json",
"description" => "The Value Type of the Metafield."
)
)
)
)
),
Error
handle - has already been taken
Yeah we can pass handle to API creation, but if it already claimed then raise error. In case we only pass title then Shopify will automatic append -2 or -3 for handle value.
Creating or Modifying Error: {"metafields":"expected Hash to be a Array"}
Delete bulk product or collection from admin (max 50 each time?) seem faster and or can be used along with bash delete script etc.
MISTAKE run API 2nd time
=> In case NEW product => Its override shopi_id in DB; Dupplicate Product (Unavailable not have handle so it can be duplicate)
May be use query to trace
select * from product where sku <= 'ABC.02090.02' and price <= 0 or qty <= 0 group by sku;
Some data need to be keep (may be go by group):
1. dr.shopi_id, dr.shopi_handle <=> shopi.id+shopi.handle
So we have dupli shopi.product
dr.shopi_id (changed), dr.shopi_handle (oh shit i forgot update this). Fortunately, we have changed to use Storefront API.
Product.handle creation not SET on create. => Can not predict.
Years multiple represent => Year in handle is confused.
Product REPRESENT MULTIPLE should have title 'ALL' in suffix.
Tool/API scan dupli/wrong product/stuff is cool but seem complex. Edit seem always difficult than Create.
Digg again to GET ACCESS TOKEN
Write some detail here.
Storefront API sortKey
First 3 plan Basic, Shopify and Advanced are 'standard' plan. And have redirect limit of 100.000.
CSV data with mixed HTML or BREAK LINE (\n)
This cause problem of 1 product spread multiple line => We can not cut large file by line without special check first.
split -b 14M product_export.csv product_exp_
Shopi limit 20M upload max. Yeah but CSV is 15mb limited, our team have experienced that, but forgot after along.
Some shit ab jquery code + shopify filter product price.
Bash login to password protected Store
curl --dump-header https://abc.myshopify.com/password?password=xxx
I do not have curl installed or Admin to install program so I tried existing one.
/c/xampp/apache/bin/curl.exe https://abc.myshopify.com/password?password=xxx --cookie-jar
/c/xampp/apache/bin/curl.exe https://abc.myshopify.com/password?password=xxx --dump-header chau02-shopi-cookie
/c/xampp/apache/bin/curl.exe https://abc.myshopify.com/password?password=xxx --cookie-jar chau02-shopi-ck [FILE to store cookie]
-b, --cookie
Remember quote URL otherwise some parameter (GET) will lost.
/c/xampp/apache/bin/curl.exe -L -b chau02-shopi-cookie 'https://abc.myshopify.com/search.json?q=CBC.02013.02+OR+REC.35002.02&view=json'
/c/xampp/apache/bin/curl.exe -L -b chau02-shopi-cookie 'https://abc.myshopify.com/search.json?q=CBC.02013.02+OR+REC.35002.02&view=json' > test.json
/c/xampp/apache/bin/curl.exe -L -b chau02-shopi-ck 'https://abc.myshopify.com/search.json?q=CBC.02013.02+OR+REC.35002.02&view=json' > test2.json
It seems that you do not have to use cookie file since curl or postman have some kind of its.
But to dig deep into this take time so I will try it later. IE. we have to update cookie each time call API ?
Liquid Variable Scope in @section @snippet, include etc
This method using simple replace as seen in many implementation of Template View.
STOREFRONT Rate limit
X-Shopify-Shop-Api-Call-Limit: 40/40
Retry-After: 2.0
Tried postman but it seem not return Api-Call-Limit in the Header.
Code try ping 4xx pages. This seem not work => Luckily I found that Guzzle have a flag to do this:
set http_errors to false so it won't raise exception stop.
set http_errors to false so it won't raise exception stop.
// inspect URL call response is error or not; Because of Guzzle try catch seem not work, so use this premitive way.
// TODO fix permission issue
protected function curlCheckErrorResponse($url) {
$url = 'https://abc.myshopify.com/admin/api/2020-04/collections/custom-cruiser-all?view=json';
Log::debug("Inspect Collection ". $url);
$handle = curl_init($url);
curl_setopt($handle, CURLOPT_RETURNTRANSFER, TRUE);
$headers = [ 'x-shopify-access-token: shpca_xxx'];
curl_setopt($handle, CURLOPT_HTTPHEADER, $headers);
/* Get the HTML or whatever is linked in $url. */
$response = curl_exec($handle);
/* Check for 404 (file not found). */
dd($httpCode);
if ($httpCode == 404) {
/* Handle 404 here. */
return true;
} else if ($httpCode > 400) {
return true;
} else {
return false;
}
return true;
}
Oh Frontend Storefront have API for product-handle.json too - like collection;
https://shop.myshopify.com/products/mercedes-benz-190dc-02.json
Comments
Post a Comment